diff --git a/src/Neo.Cryptography.BLS12_381/Fp.cs b/src/Neo.Cryptography.BLS12_381/Fp.cs index baf683e..2e76a7b 100644 --- a/src/Neo.Cryptography.BLS12_381/Fp.cs +++ b/src/Neo.Cryptography.BLS12_381/Fp.cs @@ -116,7 +116,7 @@ public override int GetHashCode() public byte[] ToArray() { - byte[] result = GC.AllocateUninitializedArray(Size); + byte[] result = new byte[Size]; TryWrite(result); return result; } @@ -141,7 +141,11 @@ public bool TryWrite(Span buffer) public override string ToString() { - return "0x" + Convert.ToHexString(ToArray()).ToLowerInvariant(); + var output = string.Empty; + foreach (var b in ToArray()) + output += b.ToString("x2"); + + return "0x" + output; } public bool LexicographicallyLargest() diff --git a/src/Neo.Cryptography.BLS12_381/Fp12.cs b/src/Neo.Cryptography.BLS12_381/Fp12.cs index ce9ae80..af91114 100644 --- a/src/Neo.Cryptography.BLS12_381/Fp12.cs +++ b/src/Neo.Cryptography.BLS12_381/Fp12.cs @@ -80,7 +80,7 @@ public override int GetHashCode() public byte[] ToArray() { - byte[] result = GC.AllocateUninitializedArray(Size); + byte[] result = new byte[Size]; TryWrite(result); return result; } diff --git a/src/Neo.Cryptography.BLS12_381/Fp2.cs b/src/Neo.Cryptography.BLS12_381/Fp2.cs index 6e2c97d..a89d43c 100644 --- a/src/Neo.Cryptography.BLS12_381/Fp2.cs +++ b/src/Neo.Cryptography.BLS12_381/Fp2.cs @@ -76,7 +76,7 @@ public override int GetHashCode() public byte[] ToArray() { - byte[] result = GC.AllocateUninitializedArray(Size); + byte[] result = new byte[Size]; TryWrite(result); return result; } diff --git a/src/Neo.Cryptography.BLS12_381/Fp6.cs b/src/Neo.Cryptography.BLS12_381/Fp6.cs index e9f61b4..6358f41 100644 --- a/src/Neo.Cryptography.BLS12_381/Fp6.cs +++ b/src/Neo.Cryptography.BLS12_381/Fp6.cs @@ -79,7 +79,7 @@ public override int GetHashCode() public byte[] ToArray() { - byte[] result = GC.AllocateUninitializedArray(Size); + byte[] result = new byte[Size]; TryWrite(result); return result; } diff --git a/src/Neo.Cryptography.BLS12_381/G1Affine.cs b/src/Neo.Cryptography.BLS12_381/G1Affine.cs index 31168cf..43de219 100644 --- a/src/Neo.Cryptography.BLS12_381/G1Affine.cs +++ b/src/Neo.Cryptography.BLS12_381/G1Affine.cs @@ -142,7 +142,7 @@ public byte[] ToCompressed() public byte[] ToUncompressed() { - byte[] res = GC.AllocateUninitializedArray(96); + byte[] res = new byte[96]; ConditionalSelect(in X, in Fp.Zero, Infinity).TryWrite(res.AsSpan(0..48)); ConditionalSelect(in Y, in Fp.Zero, Infinity).TryWrite(res.AsSpan(48..96)); diff --git a/src/Neo.Cryptography.BLS12_381/G2Affine.cs b/src/Neo.Cryptography.BLS12_381/G2Affine.cs index 35c9456..6f47cb6 100644 --- a/src/Neo.Cryptography.BLS12_381/G2Affine.cs +++ b/src/Neo.Cryptography.BLS12_381/G2Affine.cs @@ -103,7 +103,7 @@ public byte[] ToCompressed() // to guard against implementation mistakes we do not assume this. var x = ConditionalSelect(in X, in Fp2.Zero, Infinity); - var res = GC.AllocateUninitializedArray(96); + var res = new byte[96]; x.C1.TryWrite(res.AsSpan(0..48)); x.C0.TryWrite(res.AsSpan(48..96)); @@ -124,7 +124,7 @@ public byte[] ToCompressed() public byte[] ToUncompressed() { - var res = GC.AllocateUninitializedArray(192); + var res = new byte[192]; var x = ConditionalSelect(in X, in Fp2.Zero, Infinity); var y = ConditionalSelect(in Y, in Fp2.Zero, Infinity); diff --git a/src/Neo.Cryptography.BLS12_381/MathUtility.cs b/src/Neo.Cryptography.BLS12_381/MathUtility.cs index 835b42f..9b097f4 100644 --- a/src/Neo.Cryptography.BLS12_381/MathUtility.cs +++ b/src/Neo.Cryptography.BLS12_381/MathUtility.cs @@ -18,11 +18,39 @@ public static (ulong result, ulong borrow) Sbb(ulong a, ulong b, ulong borrow) public static (ulong low, ulong high) Mac(ulong z, ulong x, ulong y, ulong carry) { - ulong high = Math.BigMul(x, y, out ulong low); + ulong high = BigMul(x, y, out ulong low); (low, carry) = Adc(low, carry, 0); (high, _) = Adc(high, 0, carry); (low, carry) = Adc(low, z, 0); (high, _) = Adc(high, 0, carry); return (low, high); } + + /// Produces the full product of two unsigned 64-bit numbers. + /// The first number to multiply. + /// The second number to multiply. + /// The low 64-bit of the product of the specified numbers. + /// The high 64-bit of the product of the specified numbers. + public 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. + uint al = (uint)a; + uint ah = (uint)(a >> 32); + uint bl = (uint)b; + uint bh = (uint)(b >> 32); + + ulong mull = ((ulong)al) * bl; + ulong t = ((ulong)ah) * bl + (mull >> 32); + ulong tl = ((ulong)al) * bh + (uint)t; + + low = tl << 32 | (uint)mull; + + return ((ulong)ah) * bh + (t >> 32) + (tl >> 32); + } } diff --git a/src/Neo.Cryptography.BLS12_381/Neo.Cryptography.BLS12_381.csproj b/src/Neo.Cryptography.BLS12_381/Neo.Cryptography.BLS12_381.csproj index bd6978b..a24ee47 100644 --- a/src/Neo.Cryptography.BLS12_381/Neo.Cryptography.BLS12_381.csproj +++ b/src/Neo.Cryptography.BLS12_381/Neo.Cryptography.BLS12_381.csproj @@ -1,10 +1,15 @@ - 0.2.0 - net7.0 + 0.3.0 + netstandard2.1;net7.0 enable - enable + enable + 11.0 + + + + diff --git a/src/Neo.Cryptography.BLS12_381/Scalar.cs b/src/Neo.Cryptography.BLS12_381/Scalar.cs index d28eda8..270d9b4 100644 --- a/src/Neo.Cryptography.BLS12_381/Scalar.cs +++ b/src/Neo.Cryptography.BLS12_381/Scalar.cs @@ -29,7 +29,7 @@ internal Scalar(ulong[] values) // This internal method is only used by the constants classes. // The data must be in the correct format. // So, there is no need to do any additional checks. - this = MemoryMarshal.AsRef(MemoryMarshal.Cast(values)); + this = Unsafe.As(ref MemoryMarshal.GetReference(MemoryMarshal.Cast(values))); } public Scalar(ulong value) @@ -51,7 +51,7 @@ public static Scalar FromBytes(ReadOnlySpan data) if (data.Length != Size) throw new FormatException($"The argument `{nameof(data)}` must contain {Size} bytes."); - ref readonly Scalar ref_ = ref MemoryMarshal.AsRef(data); + ref readonly Scalar ref_ = ref Unsafe.As(ref MemoryMarshal.GetReference(data)); try { diff --git a/tests/Neo.Cryptography.BLS12_381.Tests/Neo.Cryptography.BLS12_381.Tests.csproj b/tests/Neo.Cryptography.BLS12_381.Tests/Neo.Cryptography.BLS12_381.Tests.csproj index 48c887b..2da9c2b 100644 --- a/tests/Neo.Cryptography.BLS12_381.Tests/Neo.Cryptography.BLS12_381.Tests.csproj +++ b/tests/Neo.Cryptography.BLS12_381.Tests/Neo.Cryptography.BLS12_381.Tests.csproj @@ -8,10 +8,10 @@ - - - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive