/*
*******************************************************************************
* Java Card Bitcoin Hardware Wallet
* (c) 2015 Ledger
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*******************************************************************************
*/
package com.ledger.wallet;
import javacard.framework.JCSystem;
/**
* Convert a bitcoin amount to a displayable representation for the second factor validation
* @author BTChip
*
*/
public class BCDUtils {
public static void init() {
scratch = JCSystem.makeTransientShortArray((short)(8 * 8 / 3), JCSystem.CLEAR_ON_DESELECT);
}
private static void doubleDabble(byte[] source, short sourceOffset) {
for (byte i=0; i<(short)scratch.length; i++) {
scratch[i] = (short)0;
}
byte nscratch = (byte)(8 * 8 / 3);
byte smin = (byte)(nscratch - 2);
for (byte i=0; i<8; i++) {
for (byte j=0; j<8; j++) {
short shifted_in = (((source[(short)(sourceOffset + i)] & 0xff) & ((short)(1 << (7 - j)))) != 0) ? (short)1 : (short)0;
for (byte k=smin; k<nscratch; k++) {
scratch[k] += ((scratch[k] >= 5) ? 3 : 0);
}
if (scratch[smin] >= 8) {
smin -= 1;
}
for (byte k=smin; k < (short)(nscratch - 1); k++) {
scratch[k] <<= 1;
scratch[k] &= 0x0f;
scratch[k] |= ((scratch[(short)(k + 1)] >= 8) ? 1 : 0);
}
scratch[(short)(nscratch - 1)] <<= 1;
scratch[(short)(nscratch - 1)] &= 0x0f;
scratch[(short)(nscratch - 1)] |= (shifted_in == 1 ? 1 : 0);
}
}
}
public static short hexAmountToDisplayable(byte[] source, short sourceOffset, byte[] target, short targetOffset) {
short start = targetOffset;
doubleDabble(source, sourceOffset);
short offset = (short)0;
boolean nonZero = false;
for (byte i=0; i<13; i++) {
if (!nonZero && (scratch[offset] == 0)) {
offset++;
}
else {
nonZero = true;
target[targetOffset++] = (byte)(scratch[offset++] + '0');
}
}
if (targetOffset == start) {
target[targetOffset++] = '0';
}
target[targetOffset++] = '.';
short workOffset = offset;
for (byte i=0; i<8; i++) {
boolean allZero = true;
for (byte j=i; j<8; j++) {
if (scratch[(short)(workOffset + j)] != 0) {
allZero = false;
break;
}
}
if (allZero) {
break;
}
target[targetOffset++] = (byte)(scratch[offset++] + '0');
}
if ((short)(targetOffset - start) == 2) {
targetOffset--; // only 0
}
return targetOffset;
}
private static short scratch[];
}