Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
fea075b
Updated `RandomExtensions.NextBigIneger` to use `RandomNumberGenerator`
cschuchardt88 Jun 7, 2025
7ff6fde
Merge branch 'dev' into dev/add/random-update-biginteger
shargon Jun 8, 2025
dd579ae
Merge branch 'dev' into dev/add/random-update-biginteger
Wi1l-B0t Jun 10, 2025
65612cc
Merge branch 'dev' into dev/add/random-update-biginteger
Wi1l-B0t Jun 11, 2025
032f07a
Merge branch 'dev' into dev/add/random-update-biginteger
Wi1l-B0t Jun 13, 2025
9326f47
Added `RandomNumberFactory` class to generate random numbers.
cschuchardt88 Jun 15, 2025
baa42e5
Merge branch 'dev/add/random-update-biginteger' of github.com:cschuch…
cschuchardt88 Jun 15, 2025
b0a2709
changed namespace
cschuchardt88 Jun 15, 2025
82ee255
Fixed bugs
cschuchardt88 Jun 15, 2025
c5047d3
fixed more bugs
cschuchardt88 Jun 15, 2025
b894c97
Fixed up tests and add more
cschuchardt88 Jun 15, 2025
2a3d96b
Merge branch 'dev' into dev/add/random-update-biginteger
shargon Jun 16, 2025
efd70cc
Update src/Neo.Extensions/Factories/RandomNumberFactory.cs
cschuchardt88 Jun 17, 2025
bb9b48d
Fixed per @shargon feedback
cschuchardt88 Jun 17, 2025
33a84f7
Merge branch 'dev/add/random-update-biginteger' of github.com:cschuch…
cschuchardt88 Jun 17, 2025
a2ac484
Bug fix per @vncoelho
cschuchardt88 Jun 17, 2025
7dfa3b2
Added more tests
cschuchardt88 Jun 17, 2025
56cbd58
Bug Fix
cschuchardt88 Jun 17, 2025
03ff6da
Fixed bugs in `NextBigInteger` unit tests
cschuchardt88 Jun 17, 2025
aac2d66
Merge branch 'dev' into dev/add/random-update-biginteger
cschuchardt88 Jun 18, 2025
1f2972e
Updated `RandomExtensions.NextBigIneger` to use `RandomNumberGenerator`
cschuchardt88 Jun 7, 2025
f8a8b7a
Added `RandomNumberFactory` class to generate random numbers.
cschuchardt88 Jun 15, 2025
4bc5a15
changed namespace
cschuchardt88 Jun 15, 2025
94a787f
Fixed bugs
cschuchardt88 Jun 15, 2025
6f442da
fixed more bugs
cschuchardt88 Jun 15, 2025
87d5c9c
Fixed up tests and add more
cschuchardt88 Jun 15, 2025
d73b03d
Fixed per @shargon feedback
cschuchardt88 Jun 17, 2025
1b6be40
Update src/Neo.Extensions/Factories/RandomNumberFactory.cs
cschuchardt88 Jun 17, 2025
50aab5d
Bug fix per @vncoelho
cschuchardt88 Jun 17, 2025
236135a
Added more tests
cschuchardt88 Jun 17, 2025
b08aa7a
Bug Fix
cschuchardt88 Jun 17, 2025
03774ba
Fixed bugs in `NextBigInteger` unit tests
cschuchardt88 Jun 17, 2025
20499d8
Merge branch 'dev/add/random-update-biginteger' of github.com:cschuch…
cschuchardt88 Jun 19, 2025
40ebce0
Added more tests and add `NexrBigInteger` minmax
cschuchardt88 Jun 19, 2025
a318423
Bug fixes
cschuchardt88 Jun 19, 2025
56f7ffb
Merge branch 'dev' into dev/add/random-update-biginteger
Wi1l-B0t Jun 20, 2025
8d5ba86
Merge branch 'dev' into dev/add/random-update-biginteger
cschuchardt88 Jun 21, 2025
22b5083
Merge branch 'dev' into dev/add/random-update-biginteger
cschuchardt88 Jun 21, 2025
367ffa6
`BigInteger` now uses negative numbers.
cschuchardt88 Jun 21, 2025
1fc0721
Merge branch 'dev' into dev/add/random-update-biginteger
cschuchardt88 Jun 25, 2025
9528170
Fixes to `NextBigInteger`
cschuchardt88 Jun 26, 2025
dcf1096
Fixed `BigNextInteger(MaxValue)` to calulate correctly.
cschuchardt88 Jun 26, 2025
bc64eea
Merge branch 'dev' into dev/add/random-update-biginteger
Wi1l-B0t Jun 28, 2025
6cfcc63
Merge `dev` into `this`
cschuchardt88 Jul 6, 2025
f04e730
Merge branch 'dev' into dev/add/random-update-biginteger
vncoelho Jul 7, 2025
bd8cf38
Added @vncoelho suggestions
cschuchardt88 Jul 8, 2025
82df24d
Merge branch 'dev' into dev/add/random-update-biginteger
cschuchardt88 Jul 14, 2025
217e7b6
Fixed `NextInteger` for faster resolve.
cschuchardt88 Jul 14, 2025
a5c57df
Merge branch 'dev' into dev/add/random-update-biginteger
shargon Jul 14, 2025
d9bf7be
Merge branch 'dev' into dev/add/random-update-biginteger
Wi1l-B0t Jul 15, 2025
1fa07ea
Merge branch 'dev' into dev/add/random-update-biginteger
Jul 19, 2025
4a10323
Merge branch 'dev' into dev/add/random-update-biginteger
NGDAdmin Jul 19, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/Neo.Extensions/BigIntegerExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,12 @@ public static BigInteger Sqrt(this BigInteger value)
return z;
}

internal static BigInteger GetLowPart(this BigInteger value, int bitCount)
{
var mask = (BigInteger.One << bitCount) - 1;
return value & mask;
}

/// <summary>
/// Gets the number of bits required for shortest two's complement representation of the current instance without the sign bit.
/// Note: This method is imprecise and might not work as expected with integers larger than 256 bits if less than .NET5.
Expand Down
291 changes: 291 additions & 0 deletions src/Neo.Extensions/Factories/RandomNumberFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,291 @@
// Copyright (C) 2015-2025 The Neo Project.
//
// RandomNumberFactory.cs file belongs to the neo project and is free
// software distributed under the MIT software license, see the
// accompanying file LICENSE in the main directory of the
// repository or http://www.opensource.org/licenses/mit-license.php
// for more details.
//
// Redistribution and use in source and binary forms with or without
// modifications are permitted.

using System;
using System.Buffers.Binary;
using System.Numerics;
using System.Security.Cryptography;

namespace Neo.Extensions.Factories
{
public static class RandomNumberFactory
{
public static sbyte NextSByte() =>
NextSByte(0, sbyte.MaxValue);

public static sbyte NextSByte(sbyte maxValue)
{
if (maxValue < 0)
throw new ArgumentOutOfRangeException(nameof(maxValue));

return NextSByte(0, maxValue);
}

public static sbyte NextSByte(sbyte minValue, sbyte maxValue)
{
if (minValue == maxValue) return maxValue;

if (minValue > maxValue)
throw new ArgumentOutOfRangeException(nameof(minValue));

return (sbyte)(NextUInt32((uint)(maxValue - minValue)) + minValue);
}

public static byte NextByte() =>
NextByte(0, byte.MaxValue);

public static byte NextByte(byte maxValue) =>
NextByte(0, maxValue);

public static byte NextByte(byte minValue, byte maxValue)
{
if (minValue == maxValue) return maxValue;

if (minValue > maxValue)
throw new ArgumentOutOfRangeException(nameof(minValue));

return (byte)(NextUInt32((uint)(maxValue - minValue)) + minValue);
}

public static short NextInt16() =>
NextInt16(0, short.MaxValue);

public static short NextInt16(short maxValue)
{
if (maxValue < 0)
throw new ArgumentOutOfRangeException(nameof(maxValue));

return NextInt16(0, maxValue);
}

public static short NextInt16(short minValue, short maxValue)
{
if (minValue == maxValue) return maxValue;

if (minValue > maxValue)
throw new ArgumentOutOfRangeException(nameof(minValue));

return (short)(NextUInt32((uint)(maxValue - minValue)) + minValue);
}

public static ushort NextUInt16() =>
NextUInt16(0, ushort.MaxValue);

public static ushort NextUInt16(ushort maxValue) =>
NextUInt16(0, maxValue);

public static ushort NextUInt16(ushort minValue, ushort maxValue)
{
if (minValue == maxValue) return maxValue;

if (minValue > maxValue)
throw new ArgumentOutOfRangeException(nameof(minValue));

return (ushort)(NextUInt32((uint)(maxValue - minValue)) + minValue);
}

public static int NextInt32() =>
NextInt32(0, int.MaxValue);

public static int NextInt32(int maxValue)
{
if (maxValue < 0)
throw new ArgumentOutOfRangeException(nameof(maxValue));

return NextInt32(0, maxValue);
}

public static int NextInt32(int minValue, int maxValue)
{
if (minValue == maxValue) return maxValue;

if (minValue > maxValue)
throw new ArgumentOutOfRangeException(nameof(minValue));

return (int)NextUInt32((uint)(maxValue - minValue)) + minValue;
}

public static uint NextUInt32()
{
Span<byte> longBytes = stackalloc byte[4];
RandomNumberGenerator.Fill(longBytes);
return BinaryPrimitives.ReadUInt32LittleEndian(longBytes);
}

public static uint NextUInt32(uint maxValue)
Copy link
Member

Choose a reason for hiding this comment

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

Usually this method is inclusive in the upper bound, not exclusive

Copy link
Member Author

Choose a reason for hiding this comment

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

It does inclusive, you can check the unit tests. They check for that.

Copy link
Member

Choose a reason for hiding this comment

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

if maxValue == 0 we fall into … % maxValue , which implied divide-by-zero.

like NextInt32(5, 5)) crashes.

Copy link
Member

Choose a reason for hiding this comment

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

The same happens for other Next*

Copy link
Member Author

@cschuchardt88 cschuchardt88 Jul 8, 2025

Choose a reason for hiding this comment

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

Tests do just that NextInt32(MaxValue, MaxValue). It will never be divide-by-zero. When you take zero as unsigned and subtract it from an unsigned number, it underflows to a really big number. Which is what I want to happen (just a simple way to get a really big number). Also you can 0 % 0 == 0. But it will never end up that way. No dividing is done also.

{
var randomProduct = (ulong)maxValue * NextUInt32();
var lowPart = (uint)randomProduct;

if (lowPart < maxValue)
{
var remainder = (0u - maxValue) % maxValue;

while (lowPart < remainder)
{
randomProduct = (ulong)maxValue * NextUInt32();
lowPart = (uint)randomProduct;
}
}

return (uint)(randomProduct >> 32);
}

public static uint NextUInt32(uint minValue, uint maxValue)
{
if (minValue == maxValue) return maxValue;

if (minValue > maxValue)
throw new ArgumentOutOfRangeException(nameof(minValue));

return NextUInt32(maxValue - minValue) + minValue;
}

public static long NextInt64() =>
NextInt64(0L, long.MaxValue);

public static long NextInt64(long maxValue)
{
return NextInt64(0L, maxValue);
}

public static long NextInt64(long minValue, long maxValue)
{
if (minValue == maxValue) return maxValue;

if (minValue > maxValue)
throw new ArgumentOutOfRangeException(nameof(minValue));

return (long)NextUInt64((ulong)(maxValue - minValue)) + minValue;
}

public static ulong NextUInt64()
{
Span<byte> longBytes = stackalloc byte[8];
RandomNumberGenerator.Fill(longBytes);
return BinaryPrimitives.ReadUInt64LittleEndian(longBytes);
}

public static ulong NextUInt64(ulong maxValue)
{
var randomProduct = BigMul(maxValue, NextUInt64(), out var lowPart);

if (lowPart < maxValue)
{
var remainder = (0ul - maxValue) % maxValue;

while (lowPart < remainder)
{
randomProduct = BigMul(maxValue, NextUInt64(), out lowPart);
}
}

return randomProduct;
}

public static ulong NextUInt64(ulong minValue, ulong maxValue)
{
if (minValue == maxValue) return maxValue;

if (minValue > maxValue)
throw new ArgumentOutOfRangeException(nameof(minValue));

return NextUInt64(maxValue - minValue) + minValue;
}

public static BigInteger NextBigInteger(BigInteger minValue, BigInteger maxValue)
{
if (minValue == maxValue) return maxValue;

if (minValue > maxValue)
throw new ArgumentOutOfRangeException(nameof(minValue));

return NextBigInteger(maxValue - minValue) + minValue;
}

public static BigInteger NextBigInteger(BigInteger maxValue)
{
if (maxValue.Sign < 0)
throw new ArgumentOutOfRangeException(nameof(maxValue));

var maxValueBits = maxValue.GetByteCount() * 8;
var maxValueSize = BigInteger.Pow(2, maxValueBits);

var randomProduct = maxValue * NextBigInteger(maxValueBits);
var randomProductBits = randomProduct.GetByteCount() * 8;

var lowPart = randomProduct.GetLowPart(maxValueBits);

if (lowPart < maxValue)
{
var remainder = (maxValueSize - maxValue) % maxValue;

while (lowPart < remainder)
{
randomProduct = maxValue * NextBigInteger(maxValueBits);
randomProductBits = randomProduct.GetByteCount() * 8;
lowPart = randomProduct.GetLowPart(maxValueBits);
}
}

var result = randomProduct >> (randomProductBits - maxValueBits);

// Since BigInteger doesn't have a max value or bit size
// anything over 'maxValue' return zero
if (result >= maxValue)
return BigInteger.Zero;

return result;
}

public static BigInteger NextBigInteger(int sizeInBits)
{
if (sizeInBits < 0)
throw new ArgumentException("sizeInBits must be non-negative.");

if (sizeInBits == 0)
return BigInteger.Zero;

Span<byte> b = stackalloc byte[sizeInBits / 8 + 1];
RandomNumberGenerator.Fill(b);

if (sizeInBits % 8 == 0)
b[^1] = 0;
else
b[^1] &= (byte)((1 << sizeInBits % 8) - 1);

return new BigInteger(b);
}

private static ulong BigMul(ulong a, ulong b, out ulong low)
{
// Adaptation of algorithm for multiplication
// of 32-bit unsigned integers described
// in Hacker's Delight by Henry S. Warren, Jr. (ISBN 0-201-91465-4), Chapter 8
// Basically, it's an optimized version of FOIL method applied to
// low and high dwords of each operand

// Use 32-bit uints to optimize the fallback for 32-bit platforms.
var al = (uint)a;
var ah = (uint)(a >> 32);
var bl = (uint)b;
var bh = (uint)(b >> 32);

var mull = ((ulong)al) * bl;
var t = ((ulong)ah) * bl + (mull >> 32);
var tl = ((ulong)al) * bh + (uint)t;

low = (tl << 32) | (uint)mull;

return ((ulong)ah) * bh + (t >> 32) + (tl >> 32);
}
}
}
34 changes: 0 additions & 34 deletions src/Neo.Extensions/RandomExtensions.cs

This file was deleted.

6 changes: 3 additions & 3 deletions src/Neo/Cryptography/ECC/ECFieldElement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#nullable enable

using Neo.Extensions;
using Neo.Extensions.Factories;
using System;
using System.Numerics;

Expand Down Expand Up @@ -121,11 +122,10 @@ public override int GetHashCode()
BigInteger U, V;
do
{
Random rand = new();
BigInteger P;
var P = BigInteger.Zero;
do
{
P = rand.NextBigInteger((int)_curve.Q.GetBitLength());
P = RandomNumberFactory.NextBigInteger((int)_curve.Q.GetBitLength());
}
while (P >= _curve.Q || BigInteger.ModPow(P * P - fourQ, legendreExponent, _curve.Q) != qMinusOne);
var result = FastLucasSequence(_curve.Q, P, Q, k);
Expand Down
Loading
Loading