// Based on the OV-chip 2.0 project
//
// Digital Security (DS) group at Radboud Universiteit Nijmegen
// Copyright (C) 2008, 2009
//
// Changes by Toporin for the Bitcoin SatoChip Hardware Wallet
// Sources available on https://github.com/Toporin
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 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
// General Public License in file COPYING in this or one of the
// parent directories for more details.
//
package org.satochip.applet;
import javacard.framework.Util;
public class Biginteger {
// used for +-< operations on byte arrays
private static final short digit_mask = 0xff;
private static final short digit_len = 8;
/**
* Addition with carry report. Adds other to this number. If this
* is too small for the result (i.e., an overflow occurs) the
* method returns true. Further, the result in {@code this} will
* then be the correct result of an addition modulo the first
* number that does not fit into {@code this} ({@code 2^(}{@link
* #digit_len}{@code * }{@link #size this.size}{@code )}), i.e.,
* only one leading 1 bit is missing. If there is no overflow the
* method will return false.
* <P>
*
* compute x= x+y
* operands are stored Most Signifiant Byte First
* size is the size in bytes of the operands (should be same size, padded with 0..0 if needed)
* @param other
*/
public static boolean add_carry(byte[] x, short offsetx, byte[] y, short offsety, short size)
{
short akku = 0;
short j = (short)(offsetx+size-1);
for(short i = (short)(offsety+size-1); i >= offsety; i--, j--) {
akku = (short)(akku + (x[j] & digit_mask) + (y[i] & digit_mask));
x[j] = (byte)(akku & digit_mask);
akku = (short)((akku >>> digit_len) & digit_mask);
}
return akku != 0;
}
/**
* compute x= x+1
* operands are stored Most Signifiant Byte First
* size is the size in bytes of the operand x
*/
public static boolean add1_carry(byte[] x, short offsetx, short size)
{
//short digit_mask = (short)0xff;
//short digit_len = 8;
short akku = 1; // first carry set to 1 for increment
for(short i = (short)(offsetx+size-1); i >= offsetx; i--) {
akku = (short) ((x[i] & digit_mask) + akku);
x[i] = (byte)(akku & digit_mask);
akku = (short)((akku >>> digit_len) & digit_mask);
}
return akku != 0;
}
/**
*
* Subtraction. Subtract {@code other} from {@code this} and store
* the result in {@code this}. If an overflow occurs the return
* value is true and the value of this is the correct negative
* result in two's complement. If there is no overflow the return
* value is false.
* <P>
*
* compute x= x-y
* operands are stored Most Signifiant Byte First
* size is the size in bytes of the operands (should be same size, padded with 0..0 if needed)
*/
public static boolean subtract(byte[] x, short offsetx, byte[] y, short offsety, short size) {
short subtraction_result = 0;
short carry = 0;
short i = (short)(offsetx+size-1);
short j = (short)(offsety+size-1);
for(; i >= offsetx && j >= offsety; i--, j--) {
subtraction_result = (short) ((x[i] & digit_mask) - (y[j] & digit_mask) - carry);
x[i] = (byte)(subtraction_result & digit_mask);
carry = (short)(subtraction_result < 0 ? 1 : 0);
}
return carry > 0;
}
/**
* compute x= x-1
* operands are stored Most Signifiant Byte First
* size is the size in bytes of the operand x
*/
public static boolean subtract1_carry(byte[] x, short offsetx, short size) {
short subtraction_result = 0;
short carry = 1; // first carry set to 1 for decrement
short i = (short)(offsetx+size-1);
for(; i >= offsetx; i--) {
subtraction_result = (short) ((x[i] & digit_mask) - carry);
x[i] = (byte)(subtraction_result & digit_mask);
carry = (short)(subtraction_result < 0 ? 1 : 0);
}
return carry > 0;
}
/**
* Check whether (unsigned)x is strictly smaller than (unsigned)y
* operands are stored Most Significant Byte First
* size is the size in bytes of the operands (should be same size, padded with 0..0 if needed)
* returns true if x is strictly smaller than y, false otherwise
*/
public static boolean lessThan(byte[] x, short offsetx, byte[] y, short offsety, short size) {
short xs, ys;
for(short i = offsetx, j=offsety; i < (short)(offsetx+size); i++, j++) {
xs= (short)(x[i] & digit_mask);
ys= (short)(y[j] & digit_mask);
if(xs < ys) return true;
if(xs > ys) return false;
}
return false; // in case of equality
}
/**
* Compare unsigned byte/short in java
* http://www.javamex.com/java_equivalents/unsigned_arithmetic.shtml
*/
public static boolean isStrictlyLessThanUnsigned(byte n1, byte n2) {
return (n1 < n2) ^ ((n1 < 0) != (n2 < 0));
}
public static boolean isStrictlyLessThanUnsigned(short n1, short n2) {
return (n1 < n2) ^ ((n1 < 0) != (n2 < 0));
}
/**
* Check whether x is strictly equal to 0
* operands are stored Most Signifiant Byte First (big-endian)
* size is the size in bytes of the operand
* returns true if x is equal to 0, false otherwise
*/
public static boolean equalZero(byte[] x, short offsetx, short size) {
for(short i = offsetx; i < (short)(offsetx+size); i++) {
if(x[i] != 0) return false;
}
return true;
}
public static void Shift1bit(byte[] src, short srcOffset, short size){
short rightShifts=(short)1;
short leftShifts = (short)7;
short mask= 0x00FF;
byte previousByte = src[srcOffset]; // keep the byte before modification
src[srcOffset]= (byte) (((src[srcOffset]&mask)>>rightShifts)&mask);
for(short i = (short)(srcOffset+1); i < (short)(srcOffset+size); i++) {
byte tmp = src[i];
src[i]= (byte) ( (((src[i]&mask)>>rightShifts)&mask) | ((previousByte&mask)<<leftShifts) );
previousByte= tmp;
}
}
/**
* For a Biginteger bi of given size stored in a given byte array at given offset,
* the function sets the Biginteger to zero*/
public static void setZero(byte[] x, short offsetx, short size) {
Util.arrayFillNonAtomic(x, offsetx, (short)size, (byte)0x00);
}
/**
* For a Biginteger bi of given size stored in a given byte array at given offset,
* the function sets the Biginteger LSB to value*/
public static void setByte(byte[] x, short offsetx, short size, byte value) {
setZero(x, offsetx, size);
x[(short)(offsetx+size-1)] = value;
}
/**
* For a Biginteger bi of given size stored in a given byte array at given offset,
* the function returns the least significant byte lsb if (bi==lsb) or Ox00ff otherwise*/
public static short getLSB(byte[] x, short offsetx, short size) {
for (short i= offsetx; i<(short)(offsetx+size-1); i++){
if (x[i]!=0)
return (short)0xff;
}
return (short)(x[(short)(offsetx+size-1)] & digit_mask);
}
/**
* This function swaps the bytes of Biginteger in x to Biginteger in y*/
public static void swap(byte[] x, short offsetx, byte[] y, short offsety, short size) {
for (short i= 0; i<size; i++){
y[(short)(offsety+size-i-1)]=x[(short)(offsetx+i)];
}
}
// VarInt
/* Encode a short into Bitcoin's VarInt format and return number of byte set */
public static short encodeShortToVarInt(short value, byte[] buffer, short offset) {
//if (value<((short)253)) { // signed comparison!!
if (Biginteger.isStrictlyLessThanUnsigned(value,(short)253)){
buffer[offset]=(byte)(value & 0xFF);
return (short)1;
} else {
buffer[offset++]= (byte)253;
buffer[offset++]= (byte)(value & 0xff);
buffer[offset++]= (byte)(value>>>8);
return (short)3;
}
}
/* Encode a 4-byte int into Bitcoin's VarInt format and return number of byte set */
public static short encodeVarInt(byte[] src, short src_offset, byte[] dst, short dst_offset) {
if (src[src_offset]!=0 |
src[(short)(src_offset+1)]!=0){ // 4-bytes integer
dst[dst_offset]= (byte)0xfe;
dst[(short)(dst_offset+1)]= src[(short)(src_offset+3)]; // little endian
dst[(short)(dst_offset+2)]= src[(short)(src_offset+2)];
dst[(short)(dst_offset+3)]= src[(short)(src_offset+1)];
dst[(short)(dst_offset+4)]= src[src_offset];
return (short)5;
}
else if (src[(short)(src_offset+2)]!=0 |
(src[(short)(src_offset+3)] & 0xff)>=0xfd){ // short integer
dst[dst_offset]= (byte)0xfd;
dst[(short)(dst_offset+1)]= src[(short)(src_offset+3)]; // little endian
dst[(short)(dst_offset+2)]= src[(short)(src_offset+2)];
return (short)3;
}
else{
dst[dst_offset]=src[(short)(src_offset+3)];
return (short)1;
}
}
}