commit cdc8e0cc8db6ac6f1817010a37b4aa048cb418c3 Author: Harald Wolff Date: Thu Mar 18 19:38:09 2021 +0100 Initial Commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4e82d27 --- /dev/null +++ b/.gitignore @@ -0,0 +1,40 @@ +# Autosave files +*~ + +# build +[Oo]bj/ +[Bb]in/ +packages/ +TestResults/ + +# globs +Makefile.in +*.DS_Store +*.sln.cache +*.suo +*.cache +*.pidb +*.userprefs +*.usertasks +config.log +config.make +config.status +aclocal.m4 +install-sh +autom4te.cache/ +*.user +*.tar.gz +tarballs/ +test-results/ +Thumbs.db + +# Mac bundle stuff +*.dmg +*.app + +# resharper +*_Resharper.* +*.Resharper + +# dotCover +*.dotCover diff --git a/big.impl/Makefile b/big.impl/Makefile new file mode 100644 index 0000000..68717e3 --- /dev/null +++ b/big.impl/Makefile @@ -0,0 +1,12 @@ + +OBJECTS=bigint.o +CFLAGS=-fPIC + +all: distribute + +distribute: ../ln.biginteger/libbigint.so + +../ln.biginteger/libbigint.so: $(OBJECTS) + gcc -shared -o ../ln.biginteger/libbigint.so $(OBJECTS) + + diff --git a/big.impl/bigint.c b/big.impl/bigint.c new file mode 100644 index 0000000..fe02b95 --- /dev/null +++ b/big.impl/bigint.c @@ -0,0 +1,232 @@ +#include +#include + +uint32_t one[] = { 1 }; + +int32_t max(int32_t a,int32_t b) +{ + return a>b ? a : b; +} + +int32_t big_get_length(uint32_t *op, int32_t length) +{ + for (; length > 1; length--){ + if ( + ((op[length-1] != 0) || ((op[length-2] & (1<<31))!=0)) && ((op[length-1] != 0xFFFFFFFF) || ((op[length-2] & (1<<31))==0)) + ){ + break; + } + } + return length; +} + +int32_t big_sign(uint32_t *op, int32_t length) +{ + if ((length == 1) && (op[0] == 0)) + return 0; + else if ((op[length-1] & 0x80000000) != 0) + return -1; + else + return 1; +} + +int32_t big_log2(uint32_t *op, int32_t length) +{ + if (big_sign(op, length) < 0) + { + for (int n = (length << 5)-1; n > 0; n--) + { + if ((op[(n - 1) >> 5] & (1 << ((n - 1) & 0x1F))) == 0) + { + return 1 - n; + } + } + return 0; + } else { + for (int n = length << 5; n > 0; n--) + { + if ((op[(n - 1) >> 5] & (1 << ((n - 1) & 0x1F))) != 0) + { + return n - 1; + } + } + return 0; + } +} + +int32_t big_cmp(uint32_t* op_a, int32_t length_a, uint32_t* op_b, int32_t length_b) +{ + int l = max(length_a, length_b); + for (int n=l-1; n >= 0; n--) + { + int a = n < length_a ? op_a[n] : 0; + int b = n < length_b ? op_b[n] : 0; + + if (a < b) + return -1; + else if (a > b) + return 1; + } + return 0; +} + +void big_shl(uint32_t *op, int32_t length, int32_t n) +{ + if (n > 0) + { + int step = n >> 5; + n &= 0x1F; + + for (int i = length; i > 0; i--) + { + int b1 = i - 1 - step; + int b2 = b1 - 1; + + if (b1 >= 0){ + op[i - 1] = (op[b1] << n); + if ((n != 0)&&(b2 >= 0)) + { + op[i - 1] |= ((op[b2] >> (32 - n))); + } + } else { + op[i - 1] = 0; + } + } + } +} + +void big_shr(uint32_t *op, int32_t length, int32_t n) +{ + if (n > 0) + { + int32_t s = big_sign(op, length); + int step = n >> 5; + n &= 0x1F; + + for (int i = 0; i < length; i++) + { + int b1 = i + step; + int b2 = b1 + 1; + + if (b1 < length) + { + op[i] = (op[b1] >> n); + if ((b2 == length) && (s)){ + op[i] |= ((0xffffffff << (32 - n))); + } else if ((n != 0) && (b2 < length)) + { + op[i] |= ((op[b2] << (32 - n))); + } + } else { + op[i] = s ? 0xFFFFFFFF : 0; + } + } + } +} + + +void big_add(uint32_t* op_a, int32_t length_a, uint32_t* op_b, int32_t length_b) +{ + uint64_t c = 0; + + for (int n=0;n>= 32; + + if ((c == 0) && (n > length_b)) + break; + } +} +void big_sub(uint32_t* op_a, int32_t length_a, uint32_t* op_b, int32_t length_b) +{ + uint64_t c = 0; + + for (int n=0;n>= 32; + + if ((c == 0) && (n > length_b)) + break; + } +} + +void big_twos(uint32_t *op, int32_t length) +{ + for (int n=0;n>= 32; + } + } + } +} + +void big_divmod(uint32_t* op_a, int32_t length_a, uint32_t* op_b, int32_t length_b) +{ + int sign_a = big_sign(op_a, length_a); + int sign_b = big_sign(op_b, length_b); + + uint32_t dividend[length_a]; + uint32_t divisor[length_a]; + + memset( divisor, 0x00, sizeof(divisor) ); + + memcpy( dividend, op_a, length_a << 2); + memcpy( divisor, op_b, length_b << 2); + + memset( op_a, 0x00, length_a << 2); + + if (sign_a < 0) + big_twos( dividend, length_a); + if (sign_b < 0) + big_twos( divisor, length_a); + + int lg2a, lg2b, shift; + + lg2a = big_log2(dividend, length_a); + lg2b = big_log2(divisor, length_a); + shift = lg2a - lg2b; + + if (shift > 0) + big_shl(divisor, length_a, shift); + + for (int n = 0; n <= (shift); n++) + { + big_shl(op_a, length_a, 1); + + if (big_cmp( divisor, length_a, dividend, length_a ) <= 0) + { + op_a[0] |= 1; + big_sub( dividend, length_a, divisor, length_a ); + } + + big_shr( divisor, length_b, 1); + } + + if ((sign_a < 0) != (sign_b < 0)) + big_twos(op_a, length_a); + if (sign_a < 0) + big_twos(dividend, length_a); + + memcpy( op_b, dividend, length_b << 2); +} diff --git a/big.impl/bigint.o b/big.impl/bigint.o new file mode 100644 index 0000000..090c773 Binary files /dev/null and b/big.impl/bigint.o differ diff --git a/big.impl/libbigint.so b/big.impl/libbigint.so new file mode 100755 index 0000000..34854c1 Binary files /dev/null and b/big.impl/libbigint.so differ diff --git a/ln.biginteger.sln b/ln.biginteger.sln new file mode 100644 index 0000000..3da26b7 --- /dev/null +++ b/ln.biginteger.sln @@ -0,0 +1,48 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26124.0 +MinimumVisualStudioVersion = 15.0.26124.0 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ln.biginteger", "ln.biginteger\ln.biginteger.csproj", "{25072D31-5A85-4114-8C11-37299240E494}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ln.biginteger.test", "ln.biginteger.test\ln.biginteger.test.csproj", "{4AB1ADA7-ACB3-4790-90F0-2813FC56408A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {25072D31-5A85-4114-8C11-37299240E494}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {25072D31-5A85-4114-8C11-37299240E494}.Debug|Any CPU.Build.0 = Debug|Any CPU + {25072D31-5A85-4114-8C11-37299240E494}.Debug|x64.ActiveCfg = Debug|Any CPU + {25072D31-5A85-4114-8C11-37299240E494}.Debug|x64.Build.0 = Debug|Any CPU + {25072D31-5A85-4114-8C11-37299240E494}.Debug|x86.ActiveCfg = Debug|Any CPU + {25072D31-5A85-4114-8C11-37299240E494}.Debug|x86.Build.0 = Debug|Any CPU + {25072D31-5A85-4114-8C11-37299240E494}.Release|Any CPU.ActiveCfg = Release|Any CPU + {25072D31-5A85-4114-8C11-37299240E494}.Release|Any CPU.Build.0 = Release|Any CPU + {25072D31-5A85-4114-8C11-37299240E494}.Release|x64.ActiveCfg = Release|Any CPU + {25072D31-5A85-4114-8C11-37299240E494}.Release|x64.Build.0 = Release|Any CPU + {25072D31-5A85-4114-8C11-37299240E494}.Release|x86.ActiveCfg = Release|Any CPU + {25072D31-5A85-4114-8C11-37299240E494}.Release|x86.Build.0 = Release|Any CPU + {4AB1ADA7-ACB3-4790-90F0-2813FC56408A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4AB1ADA7-ACB3-4790-90F0-2813FC56408A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4AB1ADA7-ACB3-4790-90F0-2813FC56408A}.Debug|x64.ActiveCfg = Debug|Any CPU + {4AB1ADA7-ACB3-4790-90F0-2813FC56408A}.Debug|x64.Build.0 = Debug|Any CPU + {4AB1ADA7-ACB3-4790-90F0-2813FC56408A}.Debug|x86.ActiveCfg = Debug|Any CPU + {4AB1ADA7-ACB3-4790-90F0-2813FC56408A}.Debug|x86.Build.0 = Debug|Any CPU + {4AB1ADA7-ACB3-4790-90F0-2813FC56408A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4AB1ADA7-ACB3-4790-90F0-2813FC56408A}.Release|Any CPU.Build.0 = Release|Any CPU + {4AB1ADA7-ACB3-4790-90F0-2813FC56408A}.Release|x64.ActiveCfg = Release|Any CPU + {4AB1ADA7-ACB3-4790-90F0-2813FC56408A}.Release|x64.Build.0 = Release|Any CPU + {4AB1ADA7-ACB3-4790-90F0-2813FC56408A}.Release|x86.ActiveCfg = Release|Any CPU + {4AB1ADA7-ACB3-4790-90F0-2813FC56408A}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/ln.biginteger.test/UnitTest1.cs b/ln.biginteger.test/UnitTest1.cs new file mode 100644 index 0000000..e6449ec --- /dev/null +++ b/ln.biginteger.test/UnitTest1.cs @@ -0,0 +1,84 @@ +using NUnit.Framework; + +namespace ln.biginteger.test +{ + public class Tests + { + [SetUp] + public void Setup() + { + } + + [Test] + public void Test_01_BigInteger() + { + Assert.AreEqual(1, BigInteger.Zero.GetLength()); + Assert.AreEqual(1, BigInteger.One.GetLength()); + Assert.AreEqual(2, new BigInteger(long.MaxValue).GetLength()); + Assert.AreEqual(2, new BigInteger(long.MinValue).GetLength()); + Assert.AreEqual(1, new BigInteger((long)1234).GetLength()); + + Assert.AreEqual(BigInteger.One, BigInteger.MinusOne.Twos()); + Assert.AreEqual(BigInteger.MinusOne, BigInteger.One.Twos()); + Assert.AreEqual(BigInteger.Zero, BigInteger.Zero.Twos()); + + Assert.IsTrue(BigInteger.Zero.IsZero); + Assert.IsFalse(BigInteger.One.IsZero); + + Assert.AreEqual(BigInteger.One, BigInteger.Zero.Add(BigInteger.One)); + Assert.AreEqual(BigInteger.One, BigInteger.One.Add(BigInteger.Zero)); + Assert.AreNotEqual(BigInteger.Zero, BigInteger.Zero.Add(BigInteger.One)); + + Assert.AreEqual(BigInteger.Zero, BigInteger.One.Sub(BigInteger.One)); + Assert.AreEqual(BigInteger.One, BigInteger.One.Sub(BigInteger.Zero)); + + BigInteger bi5 = new BigInteger(5 << 24); + BigInteger bi15 = new BigInteger(15 << 24 ); + BigInteger bi75 = new BigInteger(75L << 48 ); + BigInteger bi75b = bi5.Mul(bi15); + + Assert.AreEqual(bi75, bi75b); + Assert.AreEqual(new BigInteger(5), bi5 >> 24); + + + + + + Assert.Pass(); + } + + [Test] + public void Test_20_Converter() + { + foreach (string hexdigits in new string[]{ + "44BBCCDD", + "FFFFFFFF", + "1122334455667788", + "778899AABBCCDDEE" + }) + TestImplHexConvert(hexdigits); + } + + public void TestImplHexConvert(string hexdigits) + { + BigInteger bi = BigInteger.FromHexString(hexdigits); + string rehexed = bi.ToHexString(); + Assert.AreEqual(hexdigits, rehexed); + } + + + struct TestVector + { + public uint[] a,b,c; + + public TestVector(uint[] a,uint[] b, uint[] c) + { + this.a = a; + this.b = b; + this.c = c; + } + + + } + } +} \ No newline at end of file diff --git a/ln.biginteger.test/ln.biginteger.test.csproj b/ln.biginteger.test/ln.biginteger.test.csproj new file mode 100644 index 0000000..5db5206 --- /dev/null +++ b/ln.biginteger.test/ln.biginteger.test.csproj @@ -0,0 +1,17 @@ + + + + netcoreapp5.0 + + false + + + + + + + + + + + diff --git a/ln.biginteger/BigInteger.cs b/ln.biginteger/BigInteger.cs new file mode 100644 index 0000000..58a5961 --- /dev/null +++ b/ln.biginteger/BigInteger.cs @@ -0,0 +1,899 @@ +using System; +using System.Globalization; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; + +namespace ln.biginteger +{ + public class BigInteger : IComparable + { + public static readonly BigInteger Zero = new BigInteger(); + public static readonly BigInteger One = new BigInteger(1); + public static readonly BigInteger MinusOne = new BigInteger(-1); + + UInt32[] bits; + + public BigInteger() + { + this.bits = new UInt32[1]; + } + public BigInteger(UInt32 ui) + { + this.bits = new uint[]{ ui }; + } + public BigInteger(Int32 i) + { + this.bits = new uint[]{ (uint)i }; + } + + public BigInteger(UInt64 i) + { + this.bits = new uint[]{ + (uint)(i & 0xFFFFFFFF), + (uint)(i >> 32), + 0 + }; + Reduce(); + } + public BigInteger(Int64 i) + { + this.bits = new uint[]{ + (uint)(i & 0xFFFFFFFF), + (uint)(i >> 32) + }; + Reduce(); + } + + public BigInteger(UInt32[] rawbits) + { + bits = rawbits; + if (!Reduce()) + bits = (UInt32[])bits.Clone(); + } + + private bool Reduce() + { + Int32 rl = GetLength(); + if (bits.Length > rl) + { + UInt32[] newbits = new uint[rl]; + Array.Copy(bits, newbits, rl); + bits = newbits; + return true; + } + return false; + } + + public Int32 GetByteCount() => big_get_length(bits) << 2; + public Int32 GetBitLength() => big_get_length(bits) << 5; + public Int32 GetLength() => big_get_length(bits); + + public int CompareTo(BigInteger other) => big_cmp(bits, bits.Length, other.bits, other.bits.Length); + + + public Int32 Sign { + get { + if ((bits.Length == 1) && (bits[0] == 0)) + return 0; + else if ((bits[bits.Length-1] & 0x80000000) != 0) + return -1; + else + return 1; + } + } + + public bool IsZero => ((bits.Length == 1) && (bits[0] == 0)); + + + public BigInteger Add(BigInteger bi2) + { + UInt32[] r = new uint[max(bits.Length, bi2.bits.Length)+1]; + Array.Copy(bits,r,bits.Length); + big_add(r, r.Length, bi2.bits, bi2.bits.Length); + return new BigInteger(r); + } + public BigInteger Sub(BigInteger bi2) + { + UInt32[] r = new uint[max(bits.Length, bi2.bits.Length)+1]; + Array.Copy(bits,r,bits.Length); + big_sub(r, r.Length, bi2.bits, bi2.bits.Length); + return new BigInteger(r); + } + // public BigInteger Sub(BigInteger bi2) + // { + // UInt32[] r = new uint[max(bits.Length, bi2.bits.Length)+1]; + // Array.Copy(bits,r,bits.Length); + + // UInt32[] r2 = (uint[])bi2.bits.Clone(); + // big_twos(r2, r2.Length); + + // big_add(r, r.Length, r2, r2.Length); + // return new BigInteger(r); + // } + + public BigInteger Mul(BigInteger bi2) + { + UInt32[] r = new uint[bits.Length + bi2.bits.Length]; + big_smul(bits, bits.Length, bi2.bits, bi2.bits.Length, r); + return new BigInteger(r); + } + + public BigInteger DivMod(BigInteger divisor,out BigInteger remainder) + { + UInt32[] quotient = (uint[])bits.Clone(); + UInt32[] d = (uint[])divisor.bits.Clone(); + + big_divmod( quotient, quotient.Length, d, d.Length); + + remainder = new BigInteger(d); + return new BigInteger(quotient); + } + public BigInteger Div(BigInteger divisor) + { + UInt32[] quotient = (uint[])bits.Clone(); + UInt32[] d = (uint[])divisor.bits.Clone(); + + big_divmod( quotient, quotient.Length, d, d.Length); + + return new BigInteger(quotient); + } + public BigInteger Mod(BigInteger divisor) + { + UInt32[] quotient = (uint[])bits.Clone(); + UInt32[] d = (uint[])divisor.bits.Clone(); + + big_divmod( quotient, quotient.Length, d, d.Length); + + return new BigInteger(d); + } + + + + public BigInteger Ones() + { + UInt32[] r = (UInt32[])bits.Clone(); + for (int n=0;n= 0; n--) + { + for (int m=3; m>=0; m--) + { + byte tb = (byte)((bits[n] >> (m*8)) & 0xff); + if (nonzero || (tb!=0)) + { + nonzero = true; + ms.WriteByte(tb); + } + } + } + + return ms.ToArray(); + } + + + public static BigInteger operator+(BigInteger bi1,BigInteger bi2) => bi1.Add(bi2); + public static BigInteger operator-(BigInteger bi1,BigInteger bi2) => bi1.Sub(bi2); + + public static BigInteger operator<<(BigInteger bi, int n) => bi.ShiftLeft(n); + public static BigInteger operator>>(BigInteger bi, int n) => bi.ShiftRight(n); + + + + + + + + public static BigInteger FromHexString(string hex) + { + hex = hex.ToUpper(); + int length = (hex.Length+7) >> 3; + UInt32[] bits = new uint[length]; + int n; + + for (n=hex.Length-8; n>=0; n -= 8) + bits[length - 1 - (n >> 3)] = uint.Parse(hex.Substring(n,8), NumberStyles.HexNumber); + if (n > -8) + bits[length - 1] = uint.Parse(hex.Substring(0, 8 + n), NumberStyles.HexNumber); + + return new BigInteger(bits); + } + + public string ToHexString() + { + byte[] bytes = ToByteArray(); + StringBuilder sb = new StringBuilder(); + foreach (byte by in bytes) + sb.AppendFormat("{0:X2}", by); + return sb.ToString(); + } + + + + // public BigInteger(UInt32[] value) + // { + // this.bits = value; + // } + + + + + // public BigInteger(byte[] ivalue) + // { + // UInt32[] v = new UInt32[(ivalue.Length + 3) >> 2]; + // ivalue = ivalue.Segment(0, v.Length << 2); + + // for (int n = 0; n < v.Length; n++) + // { + // v[n] = BitConverter.ToUInt32(ivalue, n << 2); + // } + // this.bits = BigIntMath.reduceSigned(v); + // } + // public BigInteger(BigInteger src) + // { + // this.bits = src.bits; + // } + + // public bool IsZero => BigIntMath.isZero(bits); + // public int Sign => BigIntMath.isZero(bits) ? 0 : BigIntMath.sign(bits) ? -1 : 1; + + // public int GetByteCount() => bits.Length * 4; + // public int GetBitLength() => BigIntMath.log2(bits); + + // public byte[] ToByteArray() => bits.GetBytes(); + + // public void TryWriteBytes(Span s,out int bytesWritten) + // { + // byte[] sb = ToByteArray(); + // for (bytesWritten = 0; bytesWritten < sb.Length; bytesWritten++) + // s[bytesWritten] = sb[bytesWritten]; + // } + + // public int Log2(){ + // return BigIntMath.log2(bits); + // } + + // public static BigInteger ModPow(BigInteger i,int n,BigInteger modulus) + // { + // BigInteger r = BigInteger.One; + // while (n-- > 0) + // { + // r *= i; + // r %= modulus; + // } + // return r; + // } + + // public BigInteger Pow(int n) + // { + // if (n == 0) + // { + // return One; + // } + // else if (n == 1) + // { + // return this; + // } + // else if (n > 1) + // { + // BigInteger result = this; + // n--; + // while ((n--) > 0) + // { + // result = (result * this); + // } + // return result; + // } + // throw new ArgumentException("Integer.Pow(n): not implemented for negative exponent"); + // } + + // public BigInteger Ones() + // { + // UInt32[] result = BigIntMath.ones(bits); + // return new BigInteger(result); + // } + + // public BigInteger Twos() + // { + // UInt32[] result = BigIntMath.twos(bits); + // return new BigInteger(result); + // } + + + // public static BigInteger fromHexString(string hex) => Parse(hex, 16); + + // public override string ToString() + // { + // return String.Format("[{0}: Sign: {2,5} / {1}]", this.GetType().Name, ToString(16), Sign ); + // } + + // public string ToString(string format) + // { + // if (format.Equals("X")) + // return ToString(16); + // return ToString(10); + // } + + // public string ToString(int radix) => ToString(radix, -1); + // public string ToString(int radix, int length) + // { + // if ((radix < 2) || (radix > 36)) + // throw new ArgumentOutOfRangeException(nameof(radix)); + + // uint[] v = bits.Segment(0); + // uint[] r = new uint[]{ (uint)radix }; + + // StringBuilder sb = new StringBuilder(); + + // while ((!BigIntMath.isZero(v)) && ((length-- )!=0)) + // { + // uint[] x = BigIntMath.sdivmod(ref v, r); + // if (v[0] < 10) + // sb.Append((char)('0' + v[0])); + // else + // sb.Append((char)(55 + v[0])); + // v = x; + // } + + // char[] result = new char[sb.Length]; + // sb.CopyTo(0, result, 0, sb.Length); + // Array.Reverse(result); + // return new string(result); + // } + + // public static BigInteger Parse(string input) => Parse(input, 10); + + // public static BigInteger Parse(string input, NumberStyles numberStyles) + // { + // if ((numberStyles & (NumberStyles.HexNumber | NumberStyles.AllowHexSpecifier)) != 0) + // return Parse(input, 16); + // return Parse(input, 10); + // } + + // public static BigInteger Parse(string input, int radix) + // { + // BigInteger v = 0; + // bool sign = false; + + // if (input[0] == '-') + // { + // sign = true; + // input = input.Substring(1); + // } + + // foreach (char d in input) + // { + // int n = d - '0'; + // if (n > 9) + // n = d - 55; + + // v *= radix; + // v += n; + // } + + // if (sign) + // v = v.Twos(); + + // return v; + // } + + + + // private BigInteger __op_add(BigInteger b) + // { + // int width = (bits.Length > b.bits.Length ? bits.Length : b.bits.Length) + 1; + // UInt32[] v = BigIntMath.extendSigned(bits, width); + // UInt32[] vb = BigIntMath.extendSigned(b.bits, width); + // return new BigInteger(BigIntMath.reduceSigned(BigIntMath.add(v,vb))); + // } + // private BigInteger __op_sub(BigInteger b) + // { + // int width = (bits.Length > b.bits.Length ? bits.Length : b.bits.Length) + 1; + // UInt32[] v = BigIntMath.extendSigned(bits, width); + // UInt32[] vb = BigIntMath.extendSigned(b.bits, width); + // return new BigInteger(BigIntMath.reduceSigned(BigIntMath.sub(v,vb))); + // } + + // private int __op_cmp(BigInteger b) + // { + // return BigIntMath.cmp(bits, b.bits); + // } + + // private BigInteger __op_div(BigInteger b) + // { + // UInt32[] result = BigIntMath.sdiv(bits, b.bits); + // return new BigInteger(result); + // } + + // private BigInteger __op_mod(BigInteger b) + // { + // UInt32[] result = BigIntMath.smod(bits, b.bits); + // return new BigInteger(result); + // } + + // private BigInteger __op_mul(BigInteger b) + // { + // UInt32[] value = BigIntMath.smul(bits, b.bits); + // return new BigInteger(value); + // } + + // private BigInteger __op_new(uint[] value) + // { + // return new BigInteger(value); + // } + + // private BigInteger __op_shl(int b) + // { + // UInt32[] value = BigIntMath.extendSigned(bits, bits.Length + ((b + 31) >> 5)); + // BigIntMath.shl(value,b); + // return new BigInteger(value); + // } + + // private BigInteger __op_shr(int b) + // { + // UInt32[] value = bits.Segment(0); + // BigIntMath.shr(value, b); + // return new BigInteger(value); + // } + + // public static implicit operator BigInteger(int i) + // { + // return new BigInteger(new UInt32[]{(UInt32)i}); + // } + + + + // public static BigInteger operator +(BigInteger a, BigInteger b) + // { + // return a.__op_add(b); + // } + // public static BigInteger operator -(BigInteger a, BigInteger b) + // { + // return a.__op_sub(b); + // } + // public static BigInteger operator *(BigInteger a, BigInteger b) + // { + // return a.__op_mul(b); + // } + + // public static BigInteger operator /(BigInteger a, BigInteger b) + // { + // return a.__op_div(b); + // } + // public static BigInteger operator %(BigInteger a, BigInteger b) + // { + // return a.__op_mod(b); + // } + + // public static bool operator <(BigInteger a, BigInteger b) + // { + // return a.__op_cmp(b) < 0; + // } + // public static bool operator >(BigInteger a, BigInteger b) + // { + // return a.__op_cmp(b) > 0; + // } + // public static bool operator ==(BigInteger a, BigInteger b) + // { + // if ((object)a == (object)b) + // { + // return true; + // } + // if (((object)a == null) || ((object)b == null)) + // { + // return false; + // } + // return a.__op_cmp(b) == 0; + // } + // public static bool operator !=(BigInteger a, BigInteger b) + // { + // return a.__op_cmp(b) != 0; + // } + + // public static BigInteger operator <<(BigInteger a, int b) + // { + // return a.__op_shl(b); + // } + // public static BigInteger operator >>(BigInteger a, int b) + // { + // return a.__op_shr(b); + // } + + // public override bool Equals(object obj) => (obj is BigInteger other) && (this == other); + // public override int GetHashCode() => ToByteArray().CreateHashCode(); + + + + + + + + /*** Native Implementations ***/ + + + + + + + // public BigInteger(UInt32[] value) + // { + // this.bits = value; + // } + + + + + // public BigInteger(byte[] ivalue) + // { + // UInt32[] v = new UInt32[(ivalue.Length + 3) >> 2]; + // ivalue = ivalue.Segment(0, v.Length << 2); + + // for (int n = 0; n < v.Length; n++) + // { + // v[n] = BitConverter.ToUInt32(ivalue, n << 2); + // } + // this.bits = BigIntMath.reduceSigned(v); + // } + // public BigInteger(BigInteger src) + // { + // this.bits = src.bits; + // } + + // public bool IsZero => BigIntMath.isZero(bits); + // public int Sign => BigIntMath.isZero(bits) ? 0 : BigIntMath.sign(bits) ? -1 : 1; + + // public int GetByteCount() => bits.Length * 4; + // public int GetBitLength() => BigIntMath.log2(bits); + + // public byte[] ToByteArray() => bits.GetBytes(); + + // public void TryWriteBytes(Span s,out int bytesWritten) + // { + // byte[] sb = ToByteArray(); + // for (bytesWritten = 0; bytesWritten < sb.Length; bytesWritten++) + // s[bytesWritten] = sb[bytesWritten]; + // } + + // public int Log2(){ + // return BigIntMath.log2(bits); + // } + + // public static BigInteger ModPow(BigInteger i,int n,BigInteger modulus) + // { + // BigInteger r = BigInteger.One; + // while (n-- > 0) + // { + // r *= i; + // r %= modulus; + // } + // return r; + // } + + // public BigInteger Pow(int n) + // { + // if (n == 0) + // { + // return One; + // } + // else if (n == 1) + // { + // return this; + // } + // else if (n > 1) + // { + // BigInteger result = this; + // n--; + // while ((n--) > 0) + // { + // result = (result * this); + // } + // return result; + // } + // throw new ArgumentException("Integer.Pow(n): not implemented for negative exponent"); + // } + + // public BigInteger Ones() + // { + // UInt32[] result = BigIntMath.ones(bits); + // return new BigInteger(result); + // } + + // public BigInteger Twos() + // { + // UInt32[] result = BigIntMath.twos(bits); + // return new BigInteger(result); + // } + + + // public static BigInteger fromHexString(string hex) => Parse(hex, 16); + + // public override string ToString() + // { + // return String.Format("[{0}: Sign: {2,5} / {1}]", this.GetType().Name, ToString(16), Sign ); + // } + + // public string ToString(string format) + // { + // if (format.Equals("X")) + // return ToString(16); + // return ToString(10); + // } + + // public string ToString(int radix) => ToString(radix, -1); + // public string ToString(int radix, int length) + // { + // if ((radix < 2) || (radix > 36)) + // throw new ArgumentOutOfRangeException(nameof(radix)); + + // uint[] v = bits.Segment(0); + // uint[] r = new uint[]{ (uint)radix }; + + // StringBuilder sb = new StringBuilder(); + + // while ((!BigIntMath.isZero(v)) && ((length-- )!=0)) + // { + // uint[] x = BigIntMath.sdivmod(ref v, r); + // if (v[0] < 10) + // sb.Append((char)('0' + v[0])); + // else + // sb.Append((char)(55 + v[0])); + // v = x; + // } + + // char[] result = new char[sb.Length]; + // sb.CopyTo(0, result, 0, sb.Length); + // Array.Reverse(result); + // return new string(result); + // } + + // public static BigInteger Parse(string input) => Parse(input, 10); + + // public static BigInteger Parse(string input, NumberStyles numberStyles) + // { + // if ((numberStyles & (NumberStyles.HexNumber | NumberStyles.AllowHexSpecifier)) != 0) + // return Parse(input, 16); + // return Parse(input, 10); + // } + + // public static BigInteger Parse(string input, int radix) + // { + // BigInteger v = 0; + // bool sign = false; + + // if (input[0] == '-') + // { + // sign = true; + // input = input.Substring(1); + // } + + // foreach (char d in input) + // { + // int n = d - '0'; + // if (n > 9) + // n = d - 55; + + // v *= radix; + // v += n; + // } + + // if (sign) + // v = v.Twos(); + + // return v; + // } + + + + // private BigInteger __op_add(BigInteger b) + // { + // int width = (bits.Length > b.bits.Length ? bits.Length : b.bits.Length) + 1; + // UInt32[] v = BigIntMath.extendSigned(bits, width); + // UInt32[] vb = BigIntMath.extendSigned(b.bits, width); + // return new BigInteger(BigIntMath.reduceSigned(BigIntMath.add(v,vb))); + // } + // private BigInteger __op_sub(BigInteger b) + // { + // int width = (bits.Length > b.bits.Length ? bits.Length : b.bits.Length) + 1; + // UInt32[] v = BigIntMath.extendSigned(bits, width); + // UInt32[] vb = BigIntMath.extendSigned(b.bits, width); + // return new BigInteger(BigIntMath.reduceSigned(BigIntMath.sub(v,vb))); + // } + + // private int __op_cmp(BigInteger b) + // { + // return BigIntMath.cmp(bits, b.bits); + // } + + // private BigInteger __op_div(BigInteger b) + // { + // UInt32[] result = BigIntMath.sdiv(bits, b.bits); + // return new BigInteger(result); + // } + + // private BigInteger __op_mod(BigInteger b) + // { + // UInt32[] result = BigIntMath.smod(bits, b.bits); + // return new BigInteger(result); + // } + + // private BigInteger __op_mul(BigInteger b) + // { + // UInt32[] value = BigIntMath.smul(bits, b.bits); + // return new BigInteger(value); + // } + + // private BigInteger __op_new(uint[] value) + // { + // return new BigInteger(value); + // } + + // private BigInteger __op_shl(int b) + // { + // UInt32[] value = BigIntMath.extendSigned(bits, bits.Length + ((b + 31) >> 5)); + // BigIntMath.shl(value,b); + // return new BigInteger(value); + // } + + // private BigInteger __op_shr(int b) + // { + // UInt32[] value = bits.Segment(0); + // BigIntMath.shr(value, b); + // return new BigInteger(value); + // } + + // public static implicit operator BigInteger(int i) + // { + // return new BigInteger(new UInt32[]{(UInt32)i}); + // } + + + + // public static BigInteger operator +(BigInteger a, BigInteger b) + // { + // return a.__op_add(b); + // } + // public static BigInteger operator -(BigInteger a, BigInteger b) + // { + // return a.__op_sub(b); + // } + // public static BigInteger operator *(BigInteger a, BigInteger b) + // { + // return a.__op_mul(b); + // } + + // public static BigInteger operator /(BigInteger a, BigInteger b) + // { + // return a.__op_div(b); + // } + // public static BigInteger operator %(BigInteger a, BigInteger b) + // { + // return a.__op_mod(b); + // } + + // public static bool operator <(BigInteger a, BigInteger b) + // { + // return a.__op_cmp(b) < 0; + // } + // public static bool operator >(BigInteger a, BigInteger b) + // { + // return a.__op_cmp(b) > 0; + // } + // public static bool operator ==(BigInteger a, BigInteger b) + // { + // if ((object)a == (object)b) + // { + // return true; + // } + // if (((object)a == null) || ((object)b == null)) + // { + // return false; + // } + // return a.__op_cmp(b) == 0; + // } + // public static bool operator !=(BigInteger a, BigInteger b) + // { + // return a.__op_cmp(b) != 0; + // } + + // public static BigInteger operator <<(BigInteger a, int b) + // { + // return a.__op_shl(b); + // } + // public static BigInteger operator >>(BigInteger a, int b) + // { + // return a.__op_shr(b); + // } + + // public override bool Equals(object obj) => (obj is BigInteger other) && (this == other); + // public override int GetHashCode() => ToByteArray().CreateHashCode(); + + + + + + + + /*** Native Implementations ***/ + [DllImport("libbigint")] + public static extern Int32 big_get_length(UInt32[] bits, Int32 length); + public static Int32 big_get_length(UInt32[] bits) => big_get_length(bits, bits.Length); + + [DllImport("libbigint")] + public static extern void big_add(UInt32[] op_a, Int32 length_a, UInt32[] op_b, Int32 length_b); + [DllImport("libbigint")] + public static extern void big_sub(UInt32[] op_a, Int32 length_a, UInt32[] op_b, Int32 length_b); + + [DllImport("libbigint")] + public static extern void big_twos(UInt32[] bits, Int32 length); + [DllImport("libbigint")] + public static extern void big_shl(UInt32[] bits, Int32 length, Int32 n); + [DllImport("libbigint")] + public static extern void big_shr(UInt32[] bits, Int32 length, Int32 n); + + + [DllImport("libbigint")] + public static extern Int32 big_cmp(UInt32[] op_a, Int32 length_a, UInt32[] op_b, Int32 length_b); + + + [DllImport("libbigint")] + public static extern void big_smul(UInt32[] op_a, Int32 length_a, UInt32[] op_b, Int32 length_b, UInt32[] result); + [DllImport("libbigint")] + public static extern void big_divmod(UInt32[] op_a, Int32 length_a, UInt32[] op_b, Int32 length_b); + + + private int max(int a,int b) => a > b ? a : b; + + } +} diff --git a/ln.biginteger/NumericsExtensions.cs b/ln.biginteger/NumericsExtensions.cs new file mode 100644 index 0000000..503db67 --- /dev/null +++ b/ln.biginteger/NumericsExtensions.cs @@ -0,0 +1,36 @@ +using System; +using System.Numerics; + +namespace BigInt +{ + public static class NumericsExtensions + { + public static System.Numerics.BigInteger Sqrt(this System.Numerics.BigInteger n) + { + if (n == 0) return 0; + if (n > 0) + { + int bitLength = Convert.ToInt32(Math.Ceiling(System.Numerics.BigInteger.Log(n, 2))); + System.Numerics.BigInteger root = System.Numerics.BigInteger.One << (bitLength / 2); + + while (!isSqrt(n, root)) + { + root += n / root; + root /= 2; + } + + return root; + } + + throw new ArithmeticException("NaN"); + } + + private static Boolean isSqrt(System.Numerics.BigInteger n, System.Numerics.BigInteger root) + { + System.Numerics.BigInteger lowerBound = root * root; + System.Numerics.BigInteger upperBound = (root + 1) * (root + 1); + + return (n >= lowerBound && n < upperBound); + } + } +} diff --git a/ln.biginteger/libbigint.so b/ln.biginteger/libbigint.so new file mode 100755 index 0000000..84ceda2 Binary files /dev/null and b/ln.biginteger/libbigint.so differ diff --git a/ln.biginteger/ln.biginteger.csproj b/ln.biginteger/ln.biginteger.csproj new file mode 100644 index 0000000..108ceec --- /dev/null +++ b/ln.biginteger/ln.biginteger.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp5.0 + + + + + PreserveNewest + + + +