<p>Here's one thing I'm pretty sure is a bug, in your compact to BigInteger method:</p>

<pre><code>        ret = ret &lt;&lt; (int)amountToShift;
        amountToShift = 8 * (size - 3);
</code></pre>

<p>Ought to be:</p>

<pre><code>        amountToShift = 8 * (size - 3);
        ret = ret &lt;&lt; (int)amountToShift;
</code></pre>

<h2>EDIT</h2>

<p>Found another, in your BigInteger to compact method:</p>

<pre><code>        ret = ret &lt;&lt; (int)amountToShift2;
</code></pre>

<p>Here's the thing: ret is never used anywhere else. I'm fairly sure you meant to assign to ret2, and cast to an unsigned integer. Remember to fix both instances of this. </p>

<p>Lemme know if those two suggestions don't fix things.</p>

CC BY-SA 3.0
2013-03-04T12:58:17.407Z
Hmm  [.NET has a bug in ToString("x")](http://stackoverflow.com/q/15201965/328397)... that was throwing me off too
makerofthings7
CC BY-SA 3.0
2013-03-04T05:15:16.300Z
2013-03-04T05:36:13.757Z
2013-03-04T05:36:13.757Z
Nick ODell
<p><strong>UPDATE:</strong> The code in this question works for all test cases (Hurray!) however I don't like how <code>GetCompact</code> uses the <code>Math.Abs</code> function and don't think it's true to the OpenSSL implementation.</p>

<p>Fixing this issue will probably make this implementation "perfect"</p>

<p>The core issue (I believe) is when .NET does a bit-shift of a negative number, it expands the negative number and because it's stored in Two's compliment, the left shift extra bytes are all ones.</p>

<p>C++ likely does something different when left shifting a BigInteger, because according to the <a href="https://stackoverflow.com/q/3784996/328397">C++ spec, left shifting negative numbers is undefined.</a> </p>

<p>The solution is to use the corresponding <a href="https://stackoverflow.com/a/15329294/328397">multiplication or division instead of a shift.</a> ... I'm not sure how to do that, so your help would be appreciated.</p>

<hr>

<p>I'm working on the following C# code, and tried to make it faithful to the <a href="https://github.com/bitcoin/bitcoin/blob/master/src/bignum.h" rel="nofollow noreferrer">original C++ source.</a>  And I'm trying to get this code to match <a href="https://bitcoin.stackexchange.com/q/8045/1878">the unit tests described here.</a></p>

<p>My goal is not only to have a .NET representation of the QT data structures, but also to read and parse JSON-RPC code as well.</p>

<p><strong>C# Tests</strong></p>

<pre><code>       BigInteger bb =   BitcoinQT.SetCompact(numToCompact);


        bb = BitcoinQT.SetCompact(0x00123456);
       /*
       00000000000100100011010001010110 SetCompact:
       00000000011111111111111111111111 Bitmask &amp; (extract 0..23)
       00000000000100100011010001010110 result
       00000000000000000000000000000000 Read bytes 25..32 (&gt;&gt; 24)
       000100100011010001010110 preshifted 24
       00000000 postshifted 24
       00000000100000000000000000000000 ... check bit is neg
       00000000000000000000000000000000 ... Result

       00000000000000000000000000001100 ERROR RESULT SHOULD BE THIS 
        */
</code></pre>

<p><strong>C# code</strong></p>

<pre><code>   class BlockTargetBits
{

   static  bool debug = false;

   internal static string GetCompact(BigInteger originalBigNumber)
   {
       // 
       // 
       // Get Compact
       BigInteger num = originalBigNumber;
       byte[] numAsBytes = num.ToByteArray();
       uint compactBitsRepresentation = 0;
       uint size2;// BN_num_bytes(num);
       size2 = (uint)originalBigNumber.NumberOfBytes();
       if (size2 &lt;= 3)
       {
           uint amountToShift2 = 8 * (3 - size2);
           if (debug) Console.WriteLine(GetBits(num) + " will be shifted " + amountToShift2);
           compactBitsRepresentation = (uint)(int)(BigInteger.Abs(num) &lt;&lt; (int)amountToShift2);  // HACK: -- ABS MAY NOT BE THE CORRECT THING TO USE HERE
           if (debug) Console.WriteLine(GetBits(compactBitsRepresentation) + " was shifted " + amountToShift2);
       }
       else
       {
           BigInteger bn = num;
           uint amountToShift2 = 8 * (size2 - 3);
           if (debug) Console.WriteLine(GetBits(bn) + " will be shifted " + amountToShift2);
           var bnShifted = BigInteger.Abs(bn) &gt;&gt; (int)amountToShift2;  // HACK: -- ABS MAY NOT BE THE CORRECT THING TO USE HERE
           compactBitsRepresentation = (uint)bnShifted;
       }

       // The 0x00800000 bit denotes the sign.
       // Thus, if it is already set, divide the mantissa by 256 and increase the exponent.
       Console.WriteLine(compactBitsRepresentation.ToString("x"));
       if ((compactBitsRepresentation &amp; 0x00800000) != 0)
       {
           compactBitsRepresentation &gt;&gt;= 8;
           size2++;
       }
       if (debug) Console.WriteLine(GetBits(size2) + " size ");

       var tmp = size2 &lt;&lt; 24;
       if (debug) Console.WriteLine(GetBits(tmp) + " size (shifted to proper postion)");
       compactBitsRepresentation |= size2 &lt;&lt; 24;
       if (debug) Console.WriteLine("21 987654321 987654321 987654321");
       if (debug) Console.WriteLine(GetBits(compactBitsRepresentation) + " size # then compact");

       compactBitsRepresentation |= (num.Sign &lt; 0 ? (uint)0x00800000 : 0);

       if (compactBitsRepresentation == 0)
           return "0";
       return "0x" + compactBitsRepresentation.ToString("x8");
   }


     internal static System.Numerics.BigInteger SetCompact(uint numToCompact)
    {
        if (debug)   Console.WriteLine(GetBits(numToCompact) + " This number will be compacted ");

        //
        //  SetCompact
        // Extract the number from bits 0..23
        if (debug)  Console.WriteLine(GetBits(0x007fffff) + " Bitmask &amp; (extract 0..23) ");

        uint nWord = numToCompact &amp; 0x007fffff;
        if (debug)  Console.WriteLine(GetBits(nWord) + " result ");


        BigInteger ret = new BigInteger(nWord);

        // Add zeroes to the left according to bits 25..32
        var ttt =  ret.ToByteArray();

        uint size = numToCompact &gt;&gt; 24;
        if (debug)  Console.WriteLine(GetBits(size) + " Read bytes 25..32 (&gt;&gt; 24) ");


        uint amountToShift = 0;
        if (size &lt;= 3)
        {
            amountToShift = 8 * (3 - size);
            if (debug)  Console.WriteLine(GetBits(ret) + " preshifted " + amountToShift);

            ret = ret &gt;&gt; (int)amountToShift;
            if (debug) Console.WriteLine( GetBits(ret)+ " postshifted " + amountToShift );
        }
        else
        {
            amountToShift = 8 * (size - 3);
            if (debug) Console.WriteLine(GetBits(ret) + " preshifted " + amountToShift);

            ret = ret &lt;&lt; (int)amountToShift;

            if (debug)   Console.WriteLine(GetBits(ret) + " shifted " + amountToShift);
        }

        // Set the value negative if required per bit 24
        if (debug) Console.WriteLine(GetBits(0x00800000) + " ... check bit is neg");

        UInt32 isNegative = 0x00800000 &amp; numToCompact;

        if (debug)  Console.WriteLine(GetBits(isNegative) + " ... Result");

        if (isNegative != 0)
            ret = ret * -1;  

        var test = ret.ToByteArray();
        if (debug) Console.WriteLine(ret + " return");
        if (debug) Console.WriteLine();
        return ret;
    }

    internal static string GetHex(BigInteger bb)
    {
        if (bb == 0)
            return "0";
        else 
        return bb.ToSignedHexString().TrimStart("0".ToCharArray());
    }

    public static string GetBits(BigInteger num)
    {
        return GetBits(num.ToByteArray());

    }
    public static string GetBits(int num)
    {
        return GetBits(BitConverter.GetBytes(num));
    }
    public static string GetBits(uint num)
    {
       return  GetBits(BitConverter.GetBytes(num));
    }
    public static string GetBits(byte[] bytes)
    {
        StringBuilder sb = new StringBuilder();


        int bitPos = (8 * bytes.Length) -1;
        while (bitPos &gt;  -1)
        {
            int byteIndex = bitPos / 8;
            int offset = bitPos % 8;
            bool isSet = (bytes[byteIndex] &amp; (1 &lt;&lt; offset)) != 0;

            // isSet = [True] if the bit at bitPos is set, false otherwise
            if (isSet)
                sb.Append("1");
            else
                sb.Append("0");
            bitPos--;
        }


        return sb.ToString();
    }

}
</code></pre>

CC BY-SA 3.0
2013-03-04T04:28:00.077Z
Can you post a failing testcase?
Nick ODell
CC BY-SA 3.0
2013-03-04T04:40:45.783Z
@NickODell Lots of tests are failing... I can't figure out why
makerofthings7
CC BY-SA 3.0
2013-03-04T04:58:37.717Z
Perhaps OpenSSL bitshifting a number != .NET's implementation of bit shifting the same number
makerofthings7
CC BY-SA 3.0
2013-03-12T08:04:29.603Z
Perhaps an endianness issue. I don't know what endianness bitcoin uses, but you use native endianness. Using native endianness on a platform independent file format is always a bug, even if it might work with your current platform. Edit: Oh it's one of MS's great documentation cases which leads to a contradiction for big-endian architectures.
CodesInChaos
<development><c#><difficulty>
What is wrong with this C# code that converts a block's bits into a target?
makerofthings7
# What is wrong with this C# code that converts a block's bits into a target?

(Asked by: username_0 on 2013-03-04)

**UPDATE:** The code in this question works for all test cases (Hurray!) however I don't like how `GetCompact` uses the `Math.Abs` function and don't think it's true to the OpenSSL implementation.

Fixing this issue will probably make this implementation "perfect"

The core issue (I believe) is when .NET does a bit-shift of a negative number, it expands the negative number and because it's stored in Two's compliment, the left shift extra bytes are all ones.

C++ likely does something different when left shifting a BigInteger, because according to the [C++ spec, left shifting negative numbers is undefined.](https://stackoverflow.com/q/3784996/328397)

The solution is to use the corresponding [multiplication or division instead of a shift.](https://stackoverflow.com/a/15329294/328397) ... I'm not sure how to do that, so your help would be appreciated.

---

I'm working on the following C# code, and tried to make it faithful to the [original C++ source.](https://github.com/bitcoin/bitcoin/blob/master/src/bignum.h) And I'm trying to get this code to match [the unit tests described here.](https://bitcoin.stackexchange.com/q/8045/1878)

My goal is not only to have a .NET representation of the QT data structures, but also to read and parse JSON-RPC code as well.

**C# Tests**

```
       BigInteger bb =   BitcoinQT.SetCompact(numToCompact);

        bb = BitcoinQT.SetCompact(0x00123456);
       /*
       00000000000100100011010001010110 SetCompact:
       00000000011111111111111111111111 Bitmask & (extract 0..23)
       00000000000100100011010001010110 result
       00000000000000000000000000000000 Read bytes 25..32 (>> 24)
       000100100011010001010110 preshifted 24
       00000000 postshifted 24
       00000000100000000000000000000000 ... check bit is neg
       00000000000000000000000000000000 ... Result

       00000000000000000000000000001100 ERROR RESULT SHOULD BE THIS 
        */

```

**C# code**

```
   class BlockTargetBits
{

   static  bool debug = false;

   internal static string GetCompact(BigInteger originalBigNumber)
   {
       // 
       // 
       // Get Compact
       BigInteger num = originalBigNumber;
       byte[] numAsBytes = num.ToByteArray();
       uint compactBitsRepresentation = 0;
       uint size2;// BN_num_bytes(num);
       size2 = (uint)originalBigNumber.NumberOfBytes();
       if (size2 <= 3)
       {
           uint amountToShift2 = 8 * (3 - size2);
           if (debug) Console.WriteLine(GetBits(num) + " will be shifted " + amountToShift2);
           compactBitsRepresentation = (uint)(int)(BigInteger.Abs(num) << (int)amountToShift2);  // HACK: -- ABS MAY NOT BE THE CORRECT THING TO USE HERE
           if (debug) Console.WriteLine(GetBits(compactBitsRepresentation) + " was shifted " + amountToShift2);
       }
       else
       {
           BigInteger bn = num;
           uint amountToShift2 = 8 * (size2 - 3);
           if (debug) Console.WriteLine(GetBits(bn) + " will be shifted " + amountToShift2);
           var bnShifted = BigInteger.Abs(bn) >> (int)amountToShift2;  // HACK: -- ABS MAY NOT BE THE CORRECT THING TO USE HERE
           compactBitsRepresentation = (uint)bnShifted;
       }

       // The 0x00800000 bit denotes the sign.
       // Thus, if it is already set, divide the mantissa by 256 and increase the exponent.
       Console.WriteLine(compactBitsRepresentation.ToString("x"));
       if ((compactBitsRepresentation & 0x00800000) != 0)
       {
           compactBitsRepresentation >>= 8;
           size2++;
       }
       if (debug) Console.WriteLine(GetBits(size2) + " size ");

       var tmp = size2 << 24;
       if (debug) Console.WriteLine(GetBits(tmp) + " size (shifted to proper postion)");
       compactBitsRepresentation |= size2 << 24;
       if (debug) Console.WriteLine("21 987654321 987654321 987654321");
       if (debug) Console.WriteLine(GetBits(compactBitsRepresentation) + " size # then compact");

       compactBitsRepresentation |= (num.Sign < 0 ? (uint)0x00800000 : 0);

       if (compactBitsRepresentation == 0)
           return "0";
       return "0x" + compactBitsRepresentation.ToString("x8");
   }

     internal static System.Numerics.BigInteger SetCompact(uint numToCompact)
    {
        if (debug)   Console.WriteLine(GetBits(numToCompact) + " This number will be compacted ");

        //
        //  SetCompact
        // Extract the number from bits 0..23
        if (debug)  Console.WriteLine(GetBits(0x007fffff) + " Bitmask & (extract 0..23) ");

        uint nWord = numToCompact & 0x007fffff;
        if (debug)  Console.WriteLine(GetBits(nWord) + " result ");

        BigInteger ret = new BigInteger(nWord);

        // Add zeroes to the left according to bits 25..32
        var ttt =  ret.ToByteArray();

        uint size = numToCompact >> 24;
        if (debug)  Console.WriteLine(GetBits(size) + " Read bytes 25..32 (>> 24) ");

        uint amountToShift = 0;
        if (size <= 3)
        {
            amountToShift = 8 * (3 - size);
            if (debug)  Console.WriteLine(GetBits(ret) + " preshifted " + amountToShift);

            ret = ret >> (int)amountToShift;
            if (debug) Console.WriteLine( GetBits(ret)+ " postshifted " + amountToShift );
        }
        else
        {
            amountToShift = 8 * (size - 3);
            if (debug) Console.WriteLine(GetBits(ret) + " preshifted " + amountToShift);

            ret = ret << (int)amountToShift;

            if (debug)   Console.WriteLine(GetBits(ret) + " shifted " + amountToShift);
        }

        // Set the value negative if required per bit 24
        if (debug) Console.WriteLine(GetBits(0x00800000) + " ... check bit is neg");

        UInt32 isNegative = 0x00800000 & numToCompact;

        if (debug)  Console.WriteLine(GetBits(isNegative) + " ... Result");

        if (isNegative != 0)
            ret = ret * -1;  

        var test = ret.ToByteArray();
        if (debug) Console.WriteLine(ret + " return");
        if (debug) Console.WriteLine();
        return ret;
    }

    internal static string GetHex(BigInteger bb)
    {
        if (bb == 0)
            return "0";
        else 
        return bb.ToSignedHexString().TrimStart("0".ToCharArray());
    }

    public static string GetBits(BigInteger num)
    {
        return GetBits(num.ToByteArray());

    }
    public static string GetBits(int num)
    {
        return GetBits(BitConverter.GetBytes(num));
    }
    public static string GetBits(uint num)
    {
       return  GetBits(BitConverter.GetBytes(num));
    }
    public static string GetBits(byte[] bytes)
    {
        StringBuilder sb = new StringBuilder();

        int bitPos = (8 * bytes.Length) -1;
        while (bitPos >  -1)
        {
            int byteIndex = bitPos / 8;
            int offset = bitPos % 8;
            bool isSet = (bytes[byteIndex] & (1 << offset)) != 0;

            // isSet = [True] if the bit at bitPos is set, false otherwise
            if (isSet)
                sb.Append("1");
            else
                sb.Append("0");
            bitPos--;
        }

        return sb.ToString();
    }

}

```

**Tags:** development, c#, difficulty

> **Comments:**
> **username_1**: Can you post a failing testcase?  
> **username_0**: @username_1 Lots of tests are failing... I can't figure out why  
> **username_0**: Perhaps OpenSSL bitshifting a number != .NET's implementation of bit shifting the same number  
> **username_2**: Perhaps an endianness issue. I don't know what endianness bitcoin uses, but you use native endianness. Using native endianness on a platform independent file format is always a bug, even if it might work with your current platform. Edit: Oh it's one of MS's great documentation cases which leads to a contradiction for big-endian architectures.  

---

## 1 answers

### Answer by username_1 on 2013-03-04. Score: 3

Here's one thing I'm pretty sure is a bug, in your compact to BigInteger method:

```
        ret = ret << (int)amountToShift;
        amountToShift = 8 * (size - 3);

```

Ought to be:

```
        amountToShift = 8 * (size - 3);
        ret = ret << (int)amountToShift;

```

## EDIT

Found another, in your BigInteger to compact method:

```
        ret = ret << (int)amountToShift2;

```

Here's the thing: ret is never used anywhere else. I'm fairly sure you meant to assign to ret2, and cast to an unsigned integer. Remember to fix both instances of this.

Lemme know if those two suggestions don't fix things.

> **Comments:**
> **username_0**: Hmm  [.NET has a bug in ToString("x")](http://stackoverflow.com/q/15201965/328397)... that was throwing me off too  

---

