diff options
author | Peter Dettman <peter.dettman@bouncycastle.org> | 2023-04-20 15:32:18 +0700 |
---|---|---|
committer | Peter Dettman <peter.dettman@bouncycastle.org> | 2023-04-20 15:32:18 +0700 |
commit | caa2a7dfcc4038b83d7ff19d90c491912827f448 (patch) | |
tree | 9ee395339edd6b0a8a51f14a1a25813ccb980080 | |
parent | Refactoring in BigInteger (diff) | |
download | BouncyCastle.NET-ed25519-caa2a7dfcc4038b83d7ff19d90c491912827f448.tar.xz |
BigInteger construction from little-endian
-rw-r--r-- | crypto/src/crypto/signers/ECGOST3410Signer.cs | 6 | ||||
-rw-r--r-- | crypto/src/crypto/signers/GOST3410Signer.cs | 14 | ||||
-rw-r--r-- | crypto/src/crypto/util/Pack.cs | 40 | ||||
-rw-r--r-- | crypto/src/math/BigInteger.cs | 189 | ||||
-rw-r--r-- | crypto/src/math/raw/Nat.cs | 11 | ||||
-rw-r--r-- | crypto/src/security/PrivateKeyFactory.cs | 15 | ||||
-rw-r--r-- | crypto/src/security/PublicKeyFactory.cs | 4 |
7 files changed, 232 insertions, 47 deletions
diff --git a/crypto/src/crypto/signers/ECGOST3410Signer.cs b/crypto/src/crypto/signers/ECGOST3410Signer.cs index fd5fa4818..ba6969e39 100644 --- a/crypto/src/crypto/signers/ECGOST3410Signer.cs +++ b/crypto/src/crypto/signers/ECGOST3410Signer.cs @@ -68,8 +68,7 @@ namespace Org.BouncyCastle.Crypto.Signers if (!forSigning) throw new InvalidOperationException("not initialized for signing"); - byte[] mRev = Arrays.Reverse(message); // conversion is little-endian - BigInteger e = new BigInteger(1, mRev); + BigInteger e = new BigInteger(1, message, bigEndian: false); ECDomainParameters ec = key.Parameters; BigInteger n = ec.N; @@ -113,8 +112,7 @@ namespace Org.BouncyCastle.Crypto.Signers if (forSigning) throw new InvalidOperationException("not initialized for verification"); - byte[] mRev = Arrays.Reverse(message); // conversion is little-endian - BigInteger e = new BigInteger(1, mRev); + BigInteger e = new BigInteger(1, message, bigEndian: false); BigInteger n = key.Parameters.N; // r in the range [1,n-1] diff --git a/crypto/src/crypto/signers/GOST3410Signer.cs b/crypto/src/crypto/signers/GOST3410Signer.cs index 03aab0b04..0d80737d0 100644 --- a/crypto/src/crypto/signers/GOST3410Signer.cs +++ b/crypto/src/crypto/signers/GOST3410Signer.cs @@ -61,11 +61,9 @@ namespace Org.BouncyCastle.Crypto.Signers * * @param message the message that will be verified later. */ - public virtual BigInteger[] GenerateSignature( - byte[] message) + public virtual BigInteger[] GenerateSignature(byte[] message) { - byte[] mRev = Arrays.Reverse(message); // conversion is little-endian - BigInteger m = new BigInteger(1, mRev); + BigInteger m = new BigInteger(1, message, bigEndian: false); Gost3410Parameters parameters = key.Parameters; BigInteger k; @@ -89,13 +87,9 @@ namespace Org.BouncyCastle.Crypto.Signers * the passed in message for standard Gost3410 the message should be a * Gost3411 hash of the real message to be verified. */ - public virtual bool VerifySignature( - byte[] message, - BigInteger r, - BigInteger s) + public virtual bool VerifySignature(byte[] message, BigInteger r, BigInteger s) { - byte[] mRev = Arrays.Reverse(message); // conversion is little-endian - BigInteger m = new BigInteger(1, mRev); + BigInteger m = new BigInteger(1, message, bigEndian: false); Gost3410Parameters parameters = key.Parameters; if (r.SignValue < 0 || parameters.Q.CompareTo(r) <= 0) diff --git a/crypto/src/crypto/util/Pack.cs b/crypto/src/crypto/util/Pack.cs index 99c15484c..a4f8a834f 100644 --- a/crypto/src/crypto/util/Pack.cs +++ b/crypto/src/crypto/util/Pack.cs @@ -578,6 +578,25 @@ namespace Org.BouncyCastle.Crypto.Utilities #endif } + internal static uint LE_To_UInt32_High(byte[] bs, int off, int len) + { + return LE_To_UInt32_Low(bs, off, len) << ((4 - len) << 3); + } + + internal static uint LE_To_UInt32_Low(byte[] bs, int off, int len) + { + Debug.Assert(1 <= len && len <= 4); + + uint result = bs[off]; + int pos = 0; + for (int i = 1; i < len; ++i) + { + pos += 8; + result |= (uint)bs[off + i] << pos; + } + return result; + } + internal static void LE_To_UInt32(byte[] bs, int off, uint[] ns) { for (int i = 0; i < ns.Length; ++i) @@ -826,6 +845,27 @@ namespace Org.BouncyCastle.Crypto.Utilities } [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static uint LE_To_UInt32_High(ReadOnlySpan<byte> bs) + { + return LE_To_UInt32_Low(bs) << ((4 - bs.Length) << 3); + } + + internal static uint LE_To_UInt32_Low(ReadOnlySpan<byte> bs) + { + int len = bs.Length; + Debug.Assert(1 <= len && len <= 4); + + uint result = bs[0]; + int pos = 0; + for (int i = 1; i < len; ++i) + { + pos += 8; + result |= (uint)bs[i] << pos; + } + return result; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static ulong LE_To_UInt64(ReadOnlySpan<byte> bs) { return BinaryPrimitives.ReadUInt64LittleEndian(bs); diff --git a/crypto/src/math/BigInteger.cs b/crypto/src/math/BigInteger.cs index a98955779..7da886c4f 100644 --- a/crypto/src/math/BigInteger.cs +++ b/crypto/src/math/BigInteger.cs @@ -475,8 +475,15 @@ namespace Org.BouncyCastle.Math } public BigInteger(byte[] bytes) - : this(bytes, 0, bytes.Length) { + this.magnitude = InitBE(bytes, 0, bytes.Length, out this.sign); + } + + public BigInteger(byte[] bytes, bool bigEndian) + { + this.magnitude = bigEndian + ? InitBE(bytes, 0, bytes.Length, out this.sign) + : InitLE(bytes, 0, bytes.Length, out this.sign); } public BigInteger(byte[] bytes, int offset, int length) @@ -484,16 +491,30 @@ namespace Org.BouncyCastle.Math if (length == 0) throw new FormatException("Zero length BigInteger"); - // TODO Move this processing into MakeMagnitude (provide sign argument) + this.magnitude = InitBE(bytes, offset, length, out this.sign); + } + + public BigInteger(byte[] bytes, int offset, int length, bool bigEndian) + { + if (length <= 0) + throw new FormatException("Zero length BigInteger"); + + this.magnitude = bigEndian + ? InitBE(bytes, offset, length, out this.sign) + : InitLE(bytes, offset, length, out this.sign); + } + + private static uint[] InitBE(byte[] bytes, int offset, int length, out int sign) + { + // TODO Move this processing into MakeMagnitudeBE (provide sign argument) if ((sbyte)bytes[offset] >= 0) { - // strip leading zero bytes and return magnitude bytes - this.magnitude = MakeMagnitudeBE(bytes, offset, length); - this.sign = this.magnitude.Length > 0 ? 1 : 0; - return; + uint[] magnitude = MakeMagnitudeBE(bytes, offset, length); + sign = magnitude.Length > 0 ? 1 : 0; + return magnitude; } - this.sign = -1; + sign = -1; int end = offset + length; @@ -504,10 +525,7 @@ namespace Org.BouncyCastle.Math } if (iBval >= end) - { - this.magnitude = One.magnitude; - return; - } + return One.magnitude; int numBytes = end - iBval; @@ -534,7 +552,56 @@ namespace Org.BouncyCastle.Math inverse[index]++; - this.magnitude = MakeMagnitudeBE(inverse); + return MakeMagnitudeBE(inverse); + } + + private static uint[] InitLE(byte[] bytes, int offset, int length, out int sign) + { + int end = offset + length; + + // TODO Move this processing into MakeMagnitudeLE (provide sign argument) + if ((sbyte)bytes[end - 1] >= 0) + { + uint[] magnitude = MakeMagnitudeLE(bytes, offset, length); + sign = magnitude.Length > 0 ? 1 : 0; + return magnitude; + } + + sign = -1; + + // strip leading sign bytes + int last = length; + while (--last >= 0 && bytes[offset + last] == byte.MaxValue) + { + } + + if (last < 0) + return One.magnitude; + + int numBytes = last + 1; + +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + Span<byte> inverse = numBytes <= 512 + ? stackalloc byte[numBytes] + : new byte[numBytes]; +#else + byte[] inverse = new byte[numBytes]; +#endif + + for (int i = 0; i < numBytes; ++i) + { + inverse[i] = (byte)~bytes[offset + i]; + } + + int index = 0; + while (inverse[index] == byte.MaxValue) + { + inverse[index++] = byte.MinValue; + } + + inverse[index]++; + + return MakeMagnitudeLE(inverse); } private static uint[] MakeMagnitudeBE(byte[] bytes) @@ -600,12 +667,95 @@ namespace Org.BouncyCastle.Math } #endif + private static uint[] MakeMagnitudeLE(byte[] bytes) + { + return MakeMagnitudeLE(bytes, 0, bytes.Length); + } + + private static uint[] MakeMagnitudeLE(byte[] bytes, int offset, int length) + { +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + return MakeMagnitudeLE(bytes.AsSpan(offset, length)); +#else + // strip leading zeros + int last = length; + while (--last >= 0 && bytes[offset + last] == 0) + { + } + + if (last < 0) + return ZeroMagnitude; + + int nInts = (last + BytesPerInt) / BytesPerInt; + Debug.Assert(nInts > 0); + + uint[] magnitude = new uint[nInts]; + + int partial = last % BytesPerInt; + int first = partial + 1; + int pos = offset + last - partial; + + magnitude[0] = Pack.LE_To_UInt32_Low(bytes, pos, first); + for (int i = 1; i < nInts; ++i) + { + pos -= BytesPerInt; + magnitude[i] = Pack.LE_To_UInt32(bytes, pos); + } + Debug.Assert(pos == offset); + + return magnitude; +#endif + } + +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + private static uint[] MakeMagnitudeLE(ReadOnlySpan<byte> bytes) + { + // strip leading zeros + int last = bytes.Length; + while (--last >= 0 && bytes[last] == 0) + { + } + + if (last < 0) + return ZeroMagnitude; + + int nInts = (last + BytesPerInt) / BytesPerInt; + Debug.Assert(nInts > 0); + + uint[] magnitude = new uint[nInts]; + + int partial = last % BytesPerInt; + int first = partial + 1; + int pos = last - partial; + + magnitude[0] = Pack.LE_To_UInt32_Low(bytes.Slice(pos, first)); + for (int i = 1; i < nInts; ++i) + { + pos -= BytesPerInt; + magnitude[i] = Pack.LE_To_UInt32(bytes, pos); + } + Debug.Assert(pos == 0); + + return magnitude; + } +#endif + public BigInteger(int sign, byte[] bytes) - : this(sign, bytes, 0, bytes.Length) + : this(sign, bytes, 0, bytes.Length, true) + { + } + + public BigInteger(int sign, byte[] bytes, bool bigEndian) + : this(sign, bytes, 0, bytes.Length, bigEndian) { } public BigInteger(int sign, byte[] bytes, int offset, int length) + : this(sign, bytes, offset, length, true) + { + } + + public BigInteger(int sign, byte[] bytes, int offset, int length, bool bigEndian) { if (sign < -1 || sign > 1) throw new FormatException("Invalid sign value"); @@ -618,13 +768,20 @@ namespace Org.BouncyCastle.Math else { // copy bytes - this.magnitude = MakeMagnitudeBE(bytes, offset, length); + this.magnitude = bigEndian + ? MakeMagnitudeBE(bytes, offset, length) + : MakeMagnitudeLE(bytes, offset, length); this.sign = this.magnitude.Length < 1 ? 0 : sign; } } #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER public BigInteger(int sign, ReadOnlySpan<byte> bytes) + : this(sign, bytes, true) + { + } + + public BigInteger(int sign, ReadOnlySpan<byte> bytes, bool bigEndian) { if (sign < -1 || sign > 1) throw new FormatException("Invalid sign value"); @@ -637,7 +794,9 @@ namespace Org.BouncyCastle.Math else { // copy bytes - this.magnitude = MakeMagnitudeBE(bytes); + this.magnitude = bigEndian + ? MakeMagnitudeBE(bytes) + : MakeMagnitudeLE(bytes); this.sign = this.magnitude.Length < 1 ? 0 : sign; } } diff --git a/crypto/src/math/raw/Nat.cs b/crypto/src/math/raw/Nat.cs index 61d060b4e..f4d91b180 100644 --- a/crypto/src/math/raw/Nat.cs +++ b/crypto/src/math/raw/Nat.cs @@ -2747,14 +2747,9 @@ namespace Org.BouncyCastle.Math.Raw ? stackalloc byte[bsLen] : new byte[bsLen]; - int xPos = len; - Span<byte> t = bs; - while (--xPos >= 0) - { - Pack.UInt32_To_BE(x[xPos], t); - t = t[4..]; - } - return new BigInteger(1, bs); + Pack.UInt32_To_LE(x, bs); + + return new BigInteger(1, bs, bigEndian: false); } #endif diff --git a/crypto/src/security/PrivateKeyFactory.cs b/crypto/src/security/PrivateKeyFactory.cs index 38e571cd6..d6fa87943 100644 --- a/crypto/src/security/PrivateKeyFactory.cs +++ b/crypto/src/security/PrivateKeyFactory.cs @@ -151,7 +151,7 @@ namespace Org.BouncyCastle.Security Asn1OctetString privEnc = keyInfo.PrivateKeyData; if (privEnc.GetOctets().Length == 32 || privEnc.GetOctets().Length == 64) { - d = new BigInteger(1, Arrays.Reverse(privEnc.GetOctets())); + d = new BigInteger(1, privEnc.GetOctets(), bigEndian: false); } else { @@ -162,8 +162,8 @@ namespace Org.BouncyCastle.Security } else { - byte[] dVal = Arrays.Reverse(Asn1OctetString.GetInstance(privKey).GetOctets()); - d = new BigInteger(1, dVal); + byte[] dVal = Asn1OctetString.GetInstance(privKey).GetOctets(); + d = new BigInteger(1, dVal, bigEndian: false); } } } @@ -233,7 +233,7 @@ namespace Org.BouncyCastle.Security } else { - x = new BigInteger(1, Arrays.Reverse(Asn1OctetString.GetInstance(privKey).GetOctets())); + x = new BigInteger(1, Asn1OctetString.GetInstance(privKey).GetOctets(), bigEndian: false); } return new Gost3410PrivateKeyParameters(x, gostParams.PublicKeyParamSet); @@ -280,8 +280,7 @@ namespace Org.BouncyCastle.Security Asn1OctetString privEnc = keyInfo.PrivateKeyData; if (privEnc.GetOctets().Length == 32 || privEnc.GetOctets().Length == 64) { - byte[] dVal = Arrays.Reverse(privEnc.GetOctets()); - d = new BigInteger(1, dVal); + d = new BigInteger(1, privEnc.GetOctets(), bigEndian: false); } else { @@ -292,8 +291,8 @@ namespace Org.BouncyCastle.Security } else { - byte[] dVal = Arrays.Reverse(Asn1OctetString.GetInstance(privKey).GetOctets()); - d = new BigInteger(1, dVal); + byte[] dVal = Asn1OctetString.GetInstance(privKey).GetOctets(); + d = new BigInteger(1, dVal, bigEndian: false); } } } diff --git a/crypto/src/security/PublicKeyFactory.cs b/crypto/src/security/PublicKeyFactory.cs index 03cabbb13..d3ecef5c7 100644 --- a/crypto/src/security/PublicKeyFactory.cs +++ b/crypto/src/security/PublicKeyFactory.cs @@ -203,9 +203,9 @@ namespace Org.BouncyCastle.Security throw new ArgumentException("error recovering GOST3410_94 public key", e); } - byte[] keyBytes = Arrays.Reverse(key.GetOctets()); // was little endian + byte[] keyBytes = key.GetOctets(); - BigInteger y = new BigInteger(1, keyBytes); + BigInteger y = new BigInteger(1, keyBytes, bigEndian: false); return new Gost3410PublicKeyParameters(y, algParams.PublicKeyParamSet); } |