简体   繁体   中英

C# BigInteger equivalent in Java

While migrating an old project from C# to Java I came across this function:

private static byte[] solveChallenge(byte[] data, int offset, int level){
        var x = new BigInteger(1, data, 00 + offset, 64);
        var n = new BigInteger(1, data, 64 + offset, 64);
        Console.Out.WriteLine("x " + x);
        Console.Out.WriteLine("n " + n);
        return x.ModPow(BigInteger.Two.Pow(level), n).ToByteArrayUnsigned();
}

The first problem is that Java needs to use an int array since it doesn't support 4 bytes.

I tried to migrate this function and that's the result:

private byte[] solveChallenge(int[] dummyData, int offset, int level) {
    int[] x = Arrays.copyOfRange(dummyData, 00 + offset, 64 + offset);
    int[] n = Arrays.copyOfRange(dummyData, 64 + offset, 64 + offset + 64);
    BigInteger bigInteger = this.toBigInteger(x, offset, level);
    BigInteger bigInteger2 = this.toBigInteger(n, offset, level);
    System.out.println("bigInteger : " + bigInteger);
    System.out.println("bigInteger2 : " + bigInteger2);
    return null; //only for debugging purposes since it doesn't calculate the right value
}

private BigInteger toBigInteger(int[] data, int offset, int length) {
    byte[] array = new byte[data.length * 4];
    ByteBuffer bbuf = ByteBuffer.wrap(array);
    bbuf.order(ByteOrder.BIG_ENDIAN);
    IntBuffer ibuf = bbuf.asIntBuffer();
    ibuf.put(data);
    int pos = bbuf.position();
    return new BigInteger(1, array);
}

The byte array with the dummy data is the following:

byte[] dummyData = { 3, 184, 233, 18, 14, 29, 29, 96, 191, 154, 42, 188, 39, 129, 28, 43, 179, 155, 17, 253, 104, 150, 211, 242, 218, 37, 111, 45, 234, 231, 159, 226, 229, 241, 118, 6, 93, 154, 216, 39, 147, 240, 235, 37, 235, 4, 162, 199, 3, 146, 219, 250, 55, 145, 187, 109, 129, 154, 21, 99, 195, 213, 24, 171, 72, 186, 108, 207, 23, 245, 227, 206, 155, 28, 83, 117, 208, 52, 146, 247, 107, 86, 250, 91, 120, 132, 103, 96, 151, 135, 239, 236, 171, 105, 148, 132, 210, 164, 24, 121, 46, 63, 26, 6, 147, 66, 0, 113, 226, 228, 96, 54, 247, 58, 216, 123, 239, 127, 35, 235, 117, 225, 156, 139, 231, 191, 23, 16, 199, 0, 0, 39, 16, 24, 148, 19, 244, 58, 27, 168, 77, 144, 41, 52, 231, 216, 63, 52, 240, 101, 221, 196, 61, 210, 132, 247, 242, 148, 127, 73, 20, 136, 213, 82, 154, 2, 118, 247, 27, 193, 213, 31, 20, 107, 184, 115, 129, 102, 95, 130, 42, 105, 70, 228, 111, 211, 108, 149, 43, 200, 239, 220, 58, 61, 35, 169, 51, 37, 140, 12, 150, 126, 170, 183, 95, 104, 102, 218, 171, 207, 57, 172, 57, 179, 147, 134, 251, 49, 168, 124, 154, 198, 102, 204, 88, 99, 110, 128, 73, 0, 0, 0, 0, }
int[] dummyData = { 3, 184, 233, 18, 14, 29, 29, 96, 191, 154, 42, 188, 39, 129, 28, 43, 179, 155, 17, 253, 104, 150, 211, 242, 218, 37, 111, 45, 234, 231, 159, 226, 229, 241, 118, 6, 93, 154, 216, 39, 147, 240, 235, 37, 235, 4, 162, 199, 3, 146, 219, 250, 55, 145, 187, 109, 129, 154, 21, 99, 195, 213, 24, 171, 72, 186, 108, 207, 23, 245, 227, 206, 155, 28, 83, 117, 208, 52, 146, 247, 107, 86, 250, 91, 120, 132, 103, 96, 151, 135, 239, 236, 171, 105, 148, 132, 210, 164, 24, 121, 46, 63, 26, 6, 147, 66, 0, 113, 226, 228, 96, 54, 247, 58, 216, 123, 239, 127, 35, 235, 117, 225, 156, 139, 231, 191, 23, 16, 199, 0, 0, 39, 16, 24, 148, 19, 244, 58, 27, 168, 77, 144, 41, 52, 231, 216, 63, 52, 240, 101, 221, 196, 61, 210, 132, 247, 242, 148, 127, 73, 20, 136, 213, 82, 154, 2, 118, 247, 27, 193, 213, 31, 20, 107, 184, 115, 129, 102, 95, 130, 42, 105, 70, 228, 111, 211, 108, 149, 43, 200, 239, 220, 58, 61, 35, 169, 51, 37, 140, 12, 150, 126, 170, 183, 95, 104, 102, 218, 171, 207, 57, 172, 57, 179, 147, 134, 251, 49, 168, 124, 154, 198, 102, 204, 88, 99, 110, 128, 73, 0, 0, 0, 0, }

for both programs (the int[] for Java). Now comes the tricky part: The two console.writeLines in the C# version print out those values:

x 9684545129450563760811299662317393444224628107338840479787476089424784627212472709829491894762094799169291328402088637379520119916743215796610009247820616

n 9763871338200074467010224713304495633710029487465175174521229296454337320893449010179832428198865193070649591972415477477112413797655820164788963534901447

The java version however prints out:

bigInteger :

bigInteger2 :

The method parameters are 1 and 10000 for both programs (example for java):

testclass.solveChallenge(dummyData, 1, 10000);

Ideally bigInteger should have the same values as x and bigInteger2 like n. Where is my error? I have been searching for 5 hours but couldn't find anything wrong :/

I finally found the problem: The IntBuffer from Java imports its numbers in 4 bytes format (logically, because an int consists of 4 bytes). That's why it fills in 3 bytes with zeros and the last one with the signed value of the given value from the int array place. This command brought light into the dark:

BigInteger x = new BigInteger("9684545129450563760811299662317393444224628107338840479787476089424784627212472709829491894762094799169291328402088637379520119916743215796610009247820616")

Since I was able to get the actual BigInteger that I should have gotten. After applying x.toByteArray() I've seen that those bytes were filled in in a different way (without the three zero bytes). With double-checking the values generated by C# I found out that it strangely always nulls the first byte from the second variable (n in my case). After applying those rules I was able to get the desired values.

This is my final fix:

private byte[] solveChallenge(int[] dummyData, int offset, int level) {
    int[] x = Arrays.copyOfRange(dummyData, 00 + offset, 65 + offset);
    int[] n = Arrays.copyOfRange(dummyData, offset, 65 + offset + 64);
    n[0] = 0; //null first byte in n, don't copy this line, this only works for my problem!
    BigInteger xInt = this.toBigInteger(x, offset);
    BigInteger nInt = this.toBigInteger(n, offset);
    BigInteger inner = pow(BigInteger.valueOf(2), BigInteger.valueOf(level));
    return xInt.modPow(inner, nInt).toByteArray();
}
private BigInteger pow(BigInteger base, BigInteger exponent) {
      BigInteger result = BigInteger.ONE;
      while (exponent.signum() > 0) {
        if (exponent.testBit(0)) result = result.multiply(base);
        base = base.multiply(base);
        exponent = exponent.shiftRight(1);
      }
      return result;
}
private BigInteger toBigInteger(int[] data, int offset, int length) {
    byte[] array = new byte[data.length * 4];
    ByteBuffer bbuf = ByteBuffer.wrap(array);
    IntBuffer ibuf = bbuf.asIntBuffer();
    ibuf.put(data);
    bbuf.order(ByteOrder.BIG_ENDIAN);
    int i = 0;
    byte[] newArr = new byte[(array.length / 4)-1];
    //convert to Little-Endian like systems and only keep every fourth byte
    for(int j = 0; j < array.length-1; ++j) {
        if(j % 4 == 0 && j > 0) {
            int pos = j - 1;
            newArr[i] = array[pos]; 
            ++i;
        }
    }
    return new BigInteger(1, newArr);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM