0

I would like to use decimals represented in byte arrays (BCD format) to perform mathematical increments on the decimal values in the form of byte arrays.

An example is I would like to do 255 + 1 in maths which gives 256. When done in a binary array format, the 255 value would be 00000000FF and 1 is 0000000001 value in hexadecimal representation of bytes. The result to be expected would be 0000000100.

My following code attempts to do a 5 byte array increment of 255 by 1. My end results is 00000001FE which the last byte 0xFE is suppose to be 0x00. How do I correct my algorithm to properly perform a 5 byte array increment by only using basic binary operands (the Java environment is embedded) ?

    private static byte[] clkCtrCurr = new byte[5];
    private static byte[] inc = {0x00, 0x00, 0x00, 0x00, 0x01};
    private static byte buff;
    private static byte carry;

    public static void binAdd() {
        buff = (byte) (clkCtrCurr[4] ^ inc[4]);
        carry = (byte) (clkCtrCurr[4] & inc[4]);
        clkCtrCurr[4] = buff;
        clkCtrCurr[3] ^= carry;
        buff = (byte) (clkCtrCurr[3] ^ inc[3]);
        carry = (byte) (clkCtrCurr[3] & inc[3]);
        clkCtrCurr[3] = buff;
        clkCtrCurr[2] ^= carry;
        buff = (byte) (clkCtrCurr[2] ^ inc[2]);
        carry = (byte) (clkCtrCurr[2] & inc[2]);
        clkCtrCurr[2] = buff;
        clkCtrCurr[1] ^= carry;
        buff = (byte) (clkCtrCurr[1] ^ inc[1]);
        carry = (byte) (clkCtrCurr[1] & inc[1]);
        clkCtrCurr[1] = buff;
        clkCtrCurr[0] ^= carry;
        clkCtrCurr[0] ^= inc[0];
    }
thotheolh
  • 7,040
  • 7
  • 33
  • 49
  • What is meant by "basic binary operands"? Why don't we use + on the bytes, assign to an integer and work it out from there? – hack_on Dec 21 '15 at 03:29
  • It is on an embedded Java system (JavaCard) that may or may not support Int. The most it supports is short which is 2 bytes and some counter like HOTP requires things like 4 to 8 bytes worth of decimals that are usually processed in the system as bytes. – thotheolh Dec 21 '15 at 03:41

2 Answers2

1

BCD format means that each decimal digit (0-9) is stored in 4 bits (or 8 if unpacked), which means that the number looks decimal when printed in hex.

Example: The decimal number 123 should be stored in BCD as 0x0123 (decimal 291).

If unpacked, it would simply be 3 bytes: 0x01 0x02 0x03 or 0x010203 (decimal 66051).

So, if you wanted a 5-byte packed big-endian BCD number, i.e. a 10-digit decimal number, and you want to increment, you could do this:

private static void increment(byte[] bcd) {
    for (int i = bcd.length - 1; i >= 0; i--) {
        byte b = bcd[i];
        if ((b & 0x0F) < 0x09) {
            bcd[i] = (byte)(b + 1);
            return;
        }
        if ((b & 0xF0) < 0x90) {
            bcd[i] = (byte)((b & 0xF0) + 0x10);
            return;
        }
        bcd[i] = 0;
    }
}

Test

private static void print(byte[] bcd) {
    for (int i = 0; i < bcd.length; i++) {
        if (i != 0)
            System.out.print(' ');
        System.out.printf("%02x", bcd[i]);
    }
    System.out.println();
}
public static void main(String[] args) {
    byte[] bcd1 = { 0x00, 0x00, 0x00, 0x01, 0x23 }; // decimal 123
    for (int i = 0; i < 10; i++) {
        increment(bcd1);
        print(bcd1);
    }
    byte[] bcd2 = { (byte)0x99, (byte)0x99, (byte)0x99, (byte)0x99, (byte)0x95 }; // decimal 9_999_999_995
    for (int i = 0; i < 10; i++) {
        increment(bcd2);
        print(bcd2);
    }
}

Output

00 00 00 01 24
00 00 00 01 25
00 00 00 01 26
00 00 00 01 27
00 00 00 01 28
00 00 00 01 29
00 00 00 01 30
00 00 00 01 31
00 00 00 01 32
00 00 00 01 33
99 99 99 99 96
99 99 99 99 97
99 99 99 99 98
99 99 99 99 99
00 00 00 00 00
00 00 00 00 01
00 00 00 00 02
00 00 00 00 03
00 00 00 00 04
00 00 00 00 05
Andreas
  • 154,647
  • 11
  • 152
  • 247
1

Try this.

static byte add(byte x, byte y, byte[] result, byte index) {
    byte c = 0;
    while (y != 0) {
        byte t = (byte)(x & y);
        c |= t;
        x = (byte)(x ^ y);
        y = (byte)(t << 1);
    }
    result[index] = x;
    return (byte)((c & 0x80) != 0 ? 1 : 0);
}

static byte add(byte a, byte b, byte c, byte[] result, byte index) {
    byte carry = add(a, b, result, index);
    if (c > 0)
        carry |= add(result[index], c, result, index);
    return carry;
}

public static void add(byte[] a, byte[] b) {
    byte c = 0;
    c = add(a[4], b[4], c, a, (byte)4);
    c = add(a[3], b[3], c, a, (byte)3);
    c = add(a[2], b[2], c, a, (byte)2);
    c = add(a[1], b[1], c, a, (byte)1);
    c = add(a[0], b[0], c, a, (byte)0);
}