BTC#: DER Serialisation

Series: BTC# – Learning to Program Bitcoin in C#

« Previous: SEC Serialisation

Next: Base 58 Encoded Addresses »

DER Format for Signatures

DER format does a similar job to SEC format, encoding a pair of 256-bit numbers. There’s no compressed format because there’s no way to derive a signature’s s-component from the r-value.

DER format is a little more complicated than SEC because it allows for the encoding of negative numbers, with the sign of the number encoded by the most significant bit. This means that, to ensure all numbers are positive, a leading zero is added to all numbers that have that bit set.

The optional leading zero makes the size of the r- and s- fields vary, which means that the format needs to include length information for each component and for the total length of the serialised data.

DerSerialisation.png

Prefixing and postfixing zeroes to byte array was something I’ve found myself doing a few times. In the spirit of keeping the code DRY (“Don’t Repeat Yourself”), I’ve added byte array extension method to do this.

public static byte[] PrefixZeroes(this byte[] buffer, int count)
{
    if (count == 0) return buffer;

    var result = new byte[buffer.Length + count];
    buffer.CopyTo(result, count);
    return result;
}

The method to serialise signatures to DER format is on the Signature class.

public byte[] ToDerFormat()
{
    var rBytes = R.ToByteArray(ByteArrayFormat.BigEndianUnsigned);
    if (rBytes[0] > 127)
    {
        rBytes = rBytes.PrefixZeroes(1);
    }
    var sBytes = S.ToByteArray(ByteArrayFormat.BigEndianUnsigned);
    if (sBytes[0] > 127)
    {
        sBytes = sBytes.PrefixZeroes(1);
    }

    var totalLength = rBytes.Length + sBytes.Length + 6;
    var derBuffer = new byte[totalLength];
    derBuffer[0] = Serialisation.DER_START_MARKER;
    derBuffer[1] = (byte)(totalLength - 2);
    derBuffer[2] = Serialisation.DER_INTEGER_MARKER;
    derBuffer[3] = (byte)rBytes.Length;
    rBytes.CopyTo(derBuffer, 4);
    derBuffer[rBytes.Length + 4] = Serialisation.DER_INTEGER_MARKER;
    derBuffer[rBytes.Length + 5] = (byte)sBytes.Length;
    sBytes.CopyTo(derBuffer, rBytes.Length + 6);

    return derBuffer;
}

The code is a little more involved than the Python code in the book but it’s not complex. In C# we need to explicitly cast integers to bytes and I’ve used a buffer of the right size to copy the values into rather than concatenating as we go.

« Previous: SEC Serialisation

Next: Base 58 Encoded Addresses »

 

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s