package com.github.kmkt.util; import java.math.BigInteger; import java.util.Arrays; /** * 固定長の多倍長 unsigned 整数の四則演算・論理演算や比較などを行うユーティリティクラス * * License : MIT License */ public class FixBytesUtil { /** * int の下位1byteを byte として取り出す * @param i * @return i & 0xff */ public static byte int2byte(int i) { return (byte) (i & 0x000000ff); } /** * byte を unsigned として int に変換 * @param b * @return ((int) b & 0xff) */ public static int byte2int(byte b) { return ((int) b & 0x000000ff); } public static byte[] fill(byte[] val, byte b) { if (val == null) throw new IllegalArgumentException("val should not be null"); Arrays.fill(val, b); return val; } /** * a & b * @param a * @param b * @return */ public static byte[] and(byte[] a, byte[] b) { if (a == null) throw new IllegalArgumentException("a should not be null"); if (b == null) throw new IllegalArgumentException("b should not be null"); if (a.length != b.length) throw new IllegalArgumentException("byte array length should be same"); int len = a.length; byte[] result = new byte[len]; for (int i = 0; i < len; i++) { result[i] = (byte) ((a[i] & b[i]) & 0x000000ff); } return result; } /** * a | b * @param a * @param b * @return */ public static byte[] or(byte[] a, byte[] b) { if (a == null) throw new IllegalArgumentException("a should not be null"); if (b == null) throw new IllegalArgumentException("b should not be null"); if (a.length != b.length) throw new IllegalArgumentException("byte array length should be same"); int len = a.length; byte[] result = new byte[len]; for (int i = 0; i < len; i++) { result[i] = (byte) ((a[i] | b[i]) & 0x000000ff); } return result; } /** * a ^ b * @param a * @param b * @return */ public static byte[] xor(byte[] a, byte[] b) { if (a == null) throw new IllegalArgumentException("a should not be null"); if (b == null) throw new IllegalArgumentException("b should not be null"); if (a.length != b.length) throw new IllegalArgumentException("byte array length should be same"); int len = a.length; byte[] result = new byte[len]; for (int i = 0; i < len; i++) { result[i] = (byte) ((a[i] ^ b[i]) & 0x000000ff); } return result; } /** * ~val * @param val * @return */ public static byte[] not(byte[] val) { if (val == null) throw new IllegalArgumentException("val should not be null"); int len = val.length; byte[] result = new byte[len]; for (int i = 0; i < len; i++) { result[i] = (byte) ((~val[i]) & 0x000000ff); } return result; } /** * a + b * @param a * @param b * @return */ public static byte[] add(byte[] a, byte[] b) { if (a == null) throw new IllegalArgumentException("a should not be null"); if (b == null) throw new IllegalArgumentException("b should not be null"); if (a.length != b.length) throw new IllegalArgumentException("byte array length should be same"); int len = a.length; byte[] result = new byte[len]; int carry = 0; for (int i = len - 1; 0 <= i; i--) { int i1 = byte2int(a[i]); // 0 <= i1 <= 255(0xff) int i2 = byte2int(b[i]); // 0 <= i2 <= 255(0xff) int col = i1 + i2 + carry; carry = (col >> 8); result[i] = int2byte(col); } return result; } /** * a - b * @param a * @param b * @return */ public static byte[] subtract(byte[] a, byte[] b) { if (a == null) throw new IllegalArgumentException("b1 should not be null"); if (b == null) throw new IllegalArgumentException("b2 should not be null"); if (a.length != b.length) throw new IllegalArgumentException("byte array length should be same"); int len = a.length; byte[] result = new byte[len]; int borrow = 0; for (int i = len - 1; 0 <= i; i--) { int i1 = byte2int(a[i]); // 0 <= i1 <= 255(0xff) int i2 = byte2int(b[i]); // 0 <= i2 <= 255(0xff) int col = i1 - i2 + borrow; borrow = (col >> 8); result[i] = int2byte(col); } return result; } /** * a++ * @param a * @return */ public static byte[] inc(byte[] a) { if (a == null) throw new IllegalArgumentException("a should not be null"); int len = a.length; byte[] result = Arrays.copyOf(a, len); int carry = 1; for (int i = len - 1; 0 <= i; i--) { int i1 = byte2int(a[i]); // 0 <= i1 <= 255(0xff) int col = i1 + carry; carry = (col >> 8); result[i] = int2byte(col); if (carry == 0) // carry が 0 になれば以降は省略できる break; } return result; } /** * a-- * @param a * @return */ public static byte[] dec(byte[] a) { if (a == null) throw new IllegalArgumentException("a should not be null"); int len = a.length; byte[] result = Arrays.copyOf(a, len); int borrow = -1; for (int i = len - 1; 0 <= i; i--) { int i1 = byte2int(a[i]); // 0 <= i1 <= 255(0xff) int col = i1 + borrow; borrow = (col >> 8); result[i] = int2byte(col); if (borrow == 0) // 一度 borrow が 0 になれば以降は省略できる break; } return result; } /** * a * b * @param a * @param b * @return */ public static byte[] multiply(byte[] a, byte b) { if (a == null) throw new IllegalArgumentException("a should not be null"); int len = a.length; byte[] result = new byte[len]; int carry = 0; int i2 = byte2int(b); for (int i = len - 1; 0 <= i; i--) { int i1 = byte2int(a[i]); // 0 <= i1 <= 255(0xff) int col = i1 * i2 + carry; carry = (col >> 8); result[i] = int2byte(col); } return result; } /** * a * b * @param a * @param b * @return */ public static byte[] multiply(byte[] a, byte[] b) { if (a == null) throw new IllegalArgumentException("a should not be null"); if (b == null) throw new IllegalArgumentException("b should not be null"); if (a.length != b.length) throw new IllegalArgumentException("byte array length should be same"); int len = a.length; byte[] result = new byte[len]; for (int offset = len - 1; 0 <= offset; offset--) { int i2 = byte2int(b[offset]); // 0 <= i1 <= 255(0xff) int carry = 0; for (int i = len - 1; 0 <= i; i--) { int pos = offset - (len - 1 - i); if (pos < 0) break; int i1 = byte2int(a[i]); // 0 <= i1 <= 255(0xff) int r = byte2int(result[pos]); int col = r + i1 * i2 + carry; carry = (col >> 8); result[pos] = int2byte(col); } } return result; } /** * a / b * @param a * @param b * @return */ public static byte[] divide(byte[] a, byte[] b) { if (a == null) throw new IllegalArgumentException("a should not be null"); if (b == null) throw new IllegalArgumentException("b should not be null"); if (isZero(b)) throw new ArithmeticException("b should not be zero"); byte[] result = new byte[a.length]; if (isZero(a)) return result; // XXX ひとまず BigInteger 使った実装 BigInteger ba = new BigInteger(1, a); BigInteger bb = new BigInteger(1, b); BigInteger quotient = ba.divide(bb); byte[] val = quotient.toByteArray(); for (int i = 0; i < result.length && i < val.length; i++) { int rpos = result.length - 1 - i; int vpos = val.length - 1 - i; result[rpos] = val[vpos]; } return result; } /** * a % b * @param a * @param b * @return */ public static byte[] remainder(byte[] a, byte[] b) { if (a == null) throw new IllegalArgumentException("a should not be null"); if (b == null) throw new IllegalArgumentException("b should not be null"); if (isZero(b)) throw new ArithmeticException("b should not be zero"); byte[] result = new byte[a.length]; if (isZero(a)) return result; // XXX ひとまず BigInteger 使った実装 BigInteger ba = new BigInteger(1, a); BigInteger bb = new BigInteger(1, b); BigInteger remainder = ba.remainder(bb); byte[] val = remainder.toByteArray(); for (int i = 0; i < result.length && i < val.length; i++) { int rpos = result.length - 1 - i; int vpos = val.length - 1 - i; result[rpos] = val[vpos]; } return result; } public static double percentageOf(byte[] a) { byte[] b = new byte[a.length+1]; b[0] = 1; BigInteger v1 = new BigInteger(1, a); BigInteger v2 = new BigInteger(1, b); double vv1 = v1.doubleValue(); double vv2 = v2.doubleValue(); return vv1 / vv2; } /** * is zero * @param a * @return */ public static boolean isZero(byte[] a) { if (a == null) throw new IllegalArgumentException("a should not be null"); for (byte b : a) { if (b != 0) return false; } return true; } /** * Compare a and b * @param a * @param b * @return 0 a == b, negative a < b, positive a > b */ public static int compare(byte[] a, byte[] b) { if (a == null) throw new IllegalArgumentException("a should not be null"); if (b == null) throw new IllegalArgumentException("b should not be null"); if (a.length != b.length) throw new IllegalArgumentException("byte array length should be same"); if (a == b) return 0; for (int i = 0; i < a.length; i++) { int i1 = byte2int(a[i]); int i2 = byte2int(b[i]); if (i1 != i2) return i1 - i2; } return 0; } }