/// <summary> /// MPI encoded numbers are produced by the OpenSSL BN_bn2mpi function. /// They consist of a 4 byte big endian length field, followed by the stated number of bytes representing the number in big endian format (with a sign bit). /// </summary> /// <param name="value"></param> /// <param name="includeLength">Indicates whether the 4 byte length field should be included</param> /// <returns></returns> public static byte[] Encode(BigInteger value,bool includeLength=true) { if(value.Equals(BigInteger.Zero)) { if(!includeLength) { return new byte[0]; } return new byte[] { 0x00,0x00,0x00,0x00 }; } bool isNegative=value.CompareTo(BigInteger.Zero)<0; if(isNegative) { value=value.Negate(); } byte[] array=value.ToByteArray(); int length=array.Length; if((array[0] & 0x80)==0x80) { length++; } if(includeLength) { byte[] result=new byte[length+4]; Array.Copy(array,0,result,length-array.Length+3,array.Length); ((uint)length).ToByteArrayBe(result); if(isNegative) { result[4]|=0x80; } return result; } else { byte[] result; if(length!=array.Length) { result=new byte[length]; Array.Copy(array,0,result,1,array.Length); } else { result=array; } if(isNegative) { result[0]|=0x80; } return result; } }
/// <summary> /// MPI encoded numbers are produced by the OpenSSL BN_bn2mpi function. /// They consist of a 4 byte big endian length field, followed by the stated number of bytes representing the number in big endian format. /// </summary> public static BigInteger Decode(byte[] me,bool hasLength=true) { byte[] buffer; if(hasLength) { uint length=me.ReadUint32Be(); buffer=new byte[length]; Array.Copy(me,4,buffer,0,length); } else { buffer=me; } if(buffer.Length==0) { return BigInteger.Zero; } bool isNegative=(buffer[0] & 0x80)==0x80; if(isNegative) { buffer[0]&=0x7f; } BigInteger result=new BigInteger(buffer); return isNegative?result.Negate():result; }
public BigInteger Add( BigInteger value) { if (this.sign == 0) return value; if (this.sign != value.sign) { if (value.sign == 0) return this; if (value.sign < 0) return Subtract(value.Negate()); return value.Subtract(Negate()); } return AddToMagnitude(value.magnitude); }
public BigInteger Subtract( BigInteger n) { if (n.sign == 0) return this; if (this.sign == 0) return n.Negate(); if (this.sign != n.sign) return Add(n.Negate()); int compare = CompareNoLeadingZeroes(0, magnitude, 0, n.magnitude); if (compare == 0) return Zero; BigInteger bigun, lilun; if (compare < 0) { bigun = n; lilun = this; } else { bigun = this; lilun = n; } return new BigInteger(this.sign * compare, doSubBigLil(bigun.magnitude, lilun.magnitude), true); }
public BigInteger ModPow(BigInteger e, BigInteger m) { if (m.sign < 1) throw new ArithmeticException("Modulus must be positive"); if (m.Equals(One)) return Zero; if (e.sign == 0) return One; if (sign == 0) return Zero; bool negExp = e.sign < 0; if (negExp) e = e.Negate(); BigInteger result = this.Mod(m); if (!e.Equals(One)) { if ((m.magnitude[m.magnitude.Length - 1] & 1) == 0) { result = ModPowBarrett(result, e, m); } else { result = ModPowMonty(result, e, m, true); } } if (negExp) result = result.ModInverse(m); return result; }
public BigInteger Subtract( BigInteger value) { if (value.sign == 0) return this; if (this.sign == 0) return value.Negate(); if (this.sign != value.sign) return Add(value.Negate()); int compare = CompareTo(0, magnitude, 0, value.magnitude); if (compare == 0) return Zero; BigInteger bigun, lilun; if (compare < 0) { bigun = value; lilun = this; } else { bigun = this; lilun = value; } return new BigInteger(this.sign * compare, doSubBigLil(bigun.magnitude, lilun.magnitude), true); }
public void TestTestBit() { for (int i = 0; i < 10; ++i) { BigInteger n = new BigInteger(128, random); Assert.IsFalse(n.TestBit(128)); Assert.IsTrue(n.Negate().TestBit(128)); for (int j = 0; j < 10; ++j) { int pos = random.Next(128); bool test = n.ShiftRight(pos).Remainder(two).Equals(one); Assert.AreEqual(test, n.TestBit(pos)); } } }
public void TestShiftLeft() { for (int i = 0; i < 100; ++i) { int shift = random.Next(128); BigInteger a = new BigInteger(128 + i, random).Add(one); int bits = a.BitCount; // Make sure nBits is set BigInteger negA = a.Negate(); bits = negA.BitCount; // Make sure nBits is set BigInteger b = a.ShiftLeft(shift); BigInteger c = negA.ShiftLeft(shift); Assert.AreEqual(a.BitCount, b.BitCount); Assert.AreEqual(negA.BitCount + shift, c.BitCount); Assert.AreEqual(a.BitLength + shift, b.BitLength); Assert.AreEqual(negA.BitLength + shift, c.BitLength); int j = 0; for (; j < shift; ++j) { Assert.IsFalse(b.TestBit(j)); } for (; j < b.BitLength; ++j) { Assert.AreEqual(a.TestBit(j - shift), b.TestBit(j)); } } }
public void TestMultiply() { BigInteger one = BigInteger.One; Assert.AreEqual(one, one.Negate().Multiply(one.Negate())); for (int i = 0; i < 100; ++i) { int aLen = 64 + random.Next(64); int bLen = 64 + random.Next(64); BigInteger a = new BigInteger(aLen, random).SetBit(aLen); BigInteger b = new BigInteger(bLen, random).SetBit(bLen); BigInteger c = new BigInteger(32, random); BigInteger ab = a.Multiply(b); BigInteger bc = b.Multiply(c); Assert.AreEqual(ab.Add(bc), a.Add(c).Multiply(b)); Assert.AreEqual(ab.Subtract(bc), a.Subtract(c).Multiply(b)); } // Special tests for power of two since uses different code path internally for (int i = 0; i < 100; ++i) { int shift = random.Next(64); BigInteger a = one.ShiftLeft(shift); BigInteger b = new BigInteger(64 + random.Next(64), random); BigInteger bShift = b.ShiftLeft(shift); Assert.AreEqual(bShift, a.Multiply(b)); Assert.AreEqual(bShift.Negate(), a.Multiply(b.Negate())); Assert.AreEqual(bShift.Negate(), a.Negate().Multiply(b)); Assert.AreEqual(bShift, a.Negate().Multiply(b.Negate())); Assert.AreEqual(bShift, b.Multiply(a)); Assert.AreEqual(bShift.Negate(), b.Multiply(a.Negate())); Assert.AreEqual(bShift.Negate(), b.Negate().Multiply(a)); Assert.AreEqual(bShift, b.Negate().Multiply(a.Negate())); } }
public void TestDivideAndRemainder() { // TODO More basic tests BigInteger n = new BigInteger(48, random); BigInteger[] qr = n.DivideAndRemainder(one); Assert.AreEqual(n, qr[0]); Assert.AreEqual(zero, qr[1]); for (int rep = 0; rep < 10; ++rep) { BigInteger a = new BigInteger(100 - rep, 0, random); BigInteger b = new BigInteger(100 + rep, 0, random); BigInteger c = new BigInteger(10 + rep, 0, random); BigInteger d = a.Multiply(b).Add(c); BigInteger[] es = d.DivideAndRemainder(a); Assert.AreEqual(b, es[0]); Assert.AreEqual(c, es[1]); } // Special tests for power of two since uses different code path internally for (int i = 0; i < 100; ++i) { int shift = random.Next(64); BigInteger a = one.ShiftLeft(shift); BigInteger b = new BigInteger(64 + random.Next(64), random); BigInteger bShift = b.ShiftRight(shift); BigInteger bMod = b.And(a.Subtract(one)); string data = "shift=" + shift +", b=" + b.ToString(16); qr = b.DivideAndRemainder(a); Assert.AreEqual(bShift, qr[0], data); Assert.AreEqual(bMod, qr[1], data); qr = b.DivideAndRemainder(a.Negate()); Assert.AreEqual(bShift.Negate(), qr[0], data); Assert.AreEqual(bMod, qr[1], data); qr = b.Negate().DivideAndRemainder(a); Assert.AreEqual(bShift.Negate(), qr[0], data); Assert.AreEqual(bMod.Negate(), qr[1], data); qr = b.Negate().DivideAndRemainder(a.Negate()); Assert.AreEqual(bShift, qr[0], data); Assert.AreEqual(bMod.Negate(), qr[1], data); } }
public void TestDivide() { for (int i = -5; i <= 5; ++i) { try { val(i).Divide(zero); Assert.Fail("expected ArithmeticException"); } catch (ArithmeticException) {} } int product = 1 * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9; int productPlus = product + 1; BigInteger bigProduct = val(product); BigInteger bigProductPlus = val(productPlus); for (int divisor = 1; divisor < 10; ++divisor) { // Exact division BigInteger expected = val(product / divisor); Assert.AreEqual(expected, bigProduct.Divide(val(divisor))); Assert.AreEqual(expected.Negate(), bigProduct.Negate().Divide(val(divisor))); Assert.AreEqual(expected.Negate(), bigProduct.Divide(val(divisor).Negate())); Assert.AreEqual(expected, bigProduct.Negate().Divide(val(divisor).Negate())); expected = val((product + 1)/divisor); Assert.AreEqual(expected, bigProductPlus.Divide(val(divisor))); Assert.AreEqual(expected.Negate(), bigProductPlus.Negate().Divide(val(divisor))); Assert.AreEqual(expected.Negate(), bigProductPlus.Divide(val(divisor).Negate())); Assert.AreEqual(expected, bigProductPlus.Negate().Divide(val(divisor).Negate())); } for (int rep = 0; rep < 10; ++rep) { BigInteger a = new BigInteger(100 - rep, 0, random); BigInteger b = new BigInteger(100 + rep, 0, random); BigInteger c = new BigInteger(10 + rep, 0, random); BigInteger d = a.Multiply(b).Add(c); BigInteger e = d.Divide(a); Assert.AreEqual(b, e); } // Special tests for power of two since uses different code path internally for (int i = 0; i < 100; ++i) { int shift = random.Next(64); BigInteger a = one.ShiftLeft(shift); BigInteger b = new BigInteger(64 + random.Next(64), random); BigInteger bShift = b.ShiftRight(shift); string data = "shift=" + shift +", b=" + b.ToString(16); Assert.AreEqual(bShift, b.Divide(a), data); Assert.AreEqual(bShift.Negate(), b.Divide(a.Negate()), data); Assert.AreEqual(bShift.Negate(), b.Negate().Divide(a), data); Assert.AreEqual(bShift, b.Negate().Divide(a.Negate()), data); } // Regression { int shift = 63; BigInteger a = one.ShiftLeft(shift); BigInteger b = new BigInteger(1, Hex.Decode("2504b470dc188499")); BigInteger bShift = b.ShiftRight(shift); string data = "shift=" + shift +", b=" + b.ToString(16); Assert.AreEqual(bShift, b.Divide(a), data); Assert.AreEqual(bShift.Negate(), b.Divide(a.Negate()), data); // Assert.AreEqual(bShift.Negate(), b.Negate().Divide(a), data); Assert.AreEqual(bShift, b.Negate().Divide(a.Negate()), data); } }
public void TestBitLength() { Assert.AreEqual(0, zero.BitLength); Assert.AreEqual(1, one.BitLength); Assert.AreEqual(0, minusOne.BitLength); Assert.AreEqual(2, two.BitLength); Assert.AreEqual(1, minusTwo.BitLength); for (int i = 0; i < 100; ++i) { int bit = i + random.Next(64); BigInteger odd = new BigInteger(bit, random).SetBit(bit + 1).SetBit(0); BigInteger pow2 = one.ShiftLeft(bit); Assert.AreEqual(bit + 2, odd.BitLength); Assert.AreEqual(bit + 2, odd.Negate().BitLength); Assert.AreEqual(bit + 1, pow2.BitLength); Assert.AreEqual(bit, pow2.Negate().BitLength); } }