package org.ripple.power.utils; import java.math.BigDecimal; import java.math.BigInteger; import java.net.URLDecoder; import java.net.URLEncoder; import org.ripple.power.collection.Array; import org.ripple.power.collection.ArrayByte; import org.ripple.power.collection.LongArray; import org.ripple.power.config.LSystem; public class BigNumber { private final static String base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; class Montgomery { BigNumber m; long mt, mt2, mp, mpl, mph, um; public Montgomery(BigNumber m) { this.m = m; this.mt = m.limbs.length; this.mt2 = this.mt * 2; this.mp = m.invDigit(); this.mpl = this.mp & 0x7fff; this.mph = this.mp >> 15; this.um = (1 << (m.radix - 15)) - 1; } public BigNumber reduce(BigNumber x) { long radixMod = x.radixMask + 1; while (x.limbs.length <= this.mt2) { x.limbs.set(x.limbs.length, 0); } for (int i = 0; i < this.mt; ++i) { long j = x.limbs.get(i) & 0x7fff; long u0 = (j * this.mpl + (((j * this.mph + (x.limbs.get(i) >> 15) * this.mpl) & this.um) << 15)) & x.radixMask; j = i + this.mt; x.limbs.set( (int) j, x.limbs.get((int) j) + this.m.am(0, u0, x, i, (long) 0, this.mt)); while (x.limbs.get((int) j) >= radixMod) { x.limbs.set((int) j, x.limbs.get((int) j) - radixMod); long idx = ++j; x.limbs.set((int) idx, x.limbs.get((int) idx) + 1); } } x.trim(); x = x.shiftRight(this.mt * this.m.radix); if (x.greaterEquals(this.m) > 0) { x = x.sub(this.m); } return x.trim().normalize().reduce(); } public BigNumber square(BigNumber x) { return this.reduce(x.square()); } public BigNumber multiply(BigNumber x, BigNumber y) { return this.reduce(x.mul(y)); } public BigNumber convert(BigNumber x) { return x.abs().shiftLeft(this.mt * this.m.radix).mod(this.m); } public BigNumber revert(BigNumber x) { return this.reduce(x.copy()); }; } public static String encodeURIComponent(String s) { try { return URLEncoder.encode(s, LSystem.encoding) .replaceAll("\\+", "%20").replaceAll("\\%21", "!") .replaceAll("\\%27", "'").replaceAll("\\%28", "(") .replaceAll("\\%29", ")").replaceAll("\\%7E", "~"); } catch (Exception e) { return s; } } public static String decodeURIComponent(String s) { try { s = s.replaceAll("%20", "\\+").replaceAll("!", "\\%21") .replaceAll("'", "\\%27").replaceAll("(", "\\%28") .replaceAll(")", "\\%29").replaceAll("~", "\\%7E"); return URLDecoder.decode(s, LSystem.encoding); } catch (Exception e) { return s; } } public final static BigNumber ZERO = new BigNumber(0); public final static BigNumber ONE = new BigNumber(1); public long radix = 24; public long maxMul = 8; public LongArray limbs; public long placeVal = (long) Math.pow(2, radix); public BigDecimal ipv = new BigDecimal(1d / placeVal); public long radixMask = (1 << radix) - 1; public long exponent; public static BigNumber bn(Object it) { return new BigNumber(it); } public BigNumber(Object it) { initWith(it); } public BigNumber() { initWith(0); } public LongArray get() { return limbs; } public BigNumber copy() { return new BigNumber(this); } public String toString(boolean flag) { this.fullReduce(); String out = ""; int i; String s; LongArray l = this.limbs; for (i = 0; i < this.limbs.length; i++) { s = BigInteger.valueOf(l.get(i)).toString(16); while (i < this.limbs.length - 1 && s.length() < 6) { s = "0" + s; } out = s + out; } return flag ? "0x" + out : out; } public String toString() { return toString(true); } public BigNumber normalize() { int i = 0; BigDecimal ipv = this.ipv; long carry = 0, pv = this.placeVal, l, m, ll = limbs.length, mask = this.radixMask; for (i = 0; i < ll || (carry != 0 && carry != -1); i++) { l = JS.OR(limbs.items[i], 0).longValue() + carry; m = limbs.items[i] = l & mask; carry = ipv.multiply(BigDecimal.valueOf(l - m)).longValue(); } if (carry == -1) { limbs.items[i - 1] -= pv; } return this; } public boolean equals(BigNumber that) { int difference = 0, i; this.fullReduce(); that.fullReduce(); for (i = 0; i < this.limbs.length || i < that.limbs.length; i++) { difference = (int) (difference | this.getLimb(i) ^ that.getLimb(i)); } return (difference == 0); } public boolean equals(Object that) { if (that == null) { return false; } BigNumber newthat = new BigNumber(that); return equals(newthat); } public long greaterEquals(BigNumber that) { int less = 0, greater = 0, i; long a, b; i = Math.max(this.limbs.length, that.limbs.length) - 1; for (; i >= 0; i--) { a = this.getLimb(i); b = that.getLimb(i); int at = (int) ((b - a) & ~less); greater = (int) (greater | at); int bt = (int) ((a - b) & ~greater); less = (int) (less | bt); } return JS.MOVE_RightUShift((greater | ~less), 31); } public BigNumber[] divRem(BigNumber that) { BigNumber thisa = this.abs(), thata = that.abs(), quot = new BigNumber( 0); int ci = 0; if (!(thisa.greaterEquals(thata) > 0)) { return new BigNumber[] { new BigNumber(0), this.copy() }; } else if (thisa.equals(thata)) { return new BigNumber[] { new BigNumber(1), new BigNumber(0) }; } for (; thisa.greaterEquals(thata) > 0; ci++) { thata.doubleM(); } for (; ci > 0; ci--) { quot.doubleM(); thata.halveM(); if (thisa.greaterEquals(thata) > 0) { quot.addM(new BigNumber(1)); thisa.subM(that).normalize(); } } return new BigNumber[] { quot, thisa }; } public BigNumber divRound(BigNumber that) { BigNumber[] dr = this.divRem(that); BigNumber quot = dr[0]; BigNumber rem = dr[1]; if (rem.doubleM().greaterEquals(that) > 0) { quot.addM(new BigNumber(1)); } return quot; } public BigNumber div(BigNumber that) { BigNumber[] dr = this.divRem(that); return dr[0]; } public BigNumber addM(BigNumber that) { int i = 0; LongArray l = this.limbs, ll = that.limbs; for (i = l.length; i < ll.length; i++) { l.set(i, 0); } for (i = 0; i < ll.length; i++) { l.set(i, l.get(i) + ll.get(i)); } return this; } public BigNumber doubleM() { int i; long carry = 0, tmp, r = this.radix, m = this.radixMask; LongArray l = this.limbs; for (i = 0; i < l.length; i++) { tmp = l.get(i); tmp = tmp + tmp + carry; l.set(i, tmp & m); carry = tmp >> r; } if (carry > 0) { l.add(carry); } return this; } public BigNumber halveM() { int i; long carry = 0, tmp, r = this.radix; LongArray l = this.limbs; for (i = l.length - 1; i >= 0; i--) { tmp = l.get(i); l.set(i, (tmp + carry) >> 1); carry = (tmp & 1) << r; } if (!(l.get(l.length - 1) > 0)) { l.pop(); } return this; } public BigNumber subM(BigNumber that) { int i; LongArray l = this.limbs, ll = that.limbs; for (i = l.length; i < ll.length; i++) { l.set(i, 0); } for (i = 0; i < ll.length; i++) { l.set(i, l.get(i) - ll.get(i)); } return this; } public BigNumber trim() { LongArray l = this.limbs; long p; do { p = l.pop(); } while (l.length > 0 && p == 0); l.push(p); return this; } public BigNumber mod(BigNumber that) { boolean neg = !(this.greaterEquals(BigNumber.ZERO) > 0); that = new BigNumber(that).normalize(); BigNumber out = new BigNumber(this).normalize(); int ci = 0; if (neg) { out = (new BigNumber(0)).subM(out).normalize(); } for (; out.greaterEquals(that) > 0; ci++) { that.doubleM(); } if (neg) { out = that.sub(out).normalize(); } for (; ci > 0; ci--) { that.halveM(); if (out.greaterEquals(that) > 0) { out.subM(that).normalize(); } } return out.trim(); } public BigNumber add(BigNumber that) { return this.copy().addM(that); } public BigNumber sub(BigNumber that) { return this.copy().subM(that); } public BigNumber inverseMod(BigNumber p) { BigNumber a = new BigNumber(1), b = new BigNumber(0), x = new BigNumber( this), y = new BigNumber(p), tmp; int i, nz = 1; if (!((p.limbs.get(0) & 1) > 0)) { throw new RuntimeException("inverseMod: p must be odd"); } do { if ((x.limbs.get(0) & 1) > 0) { if (!(x.greaterEquals(y) > 0)) { tmp = x; x = y; y = tmp; tmp = a; a = b; b = tmp; } x.subM(y); x.normalize(); if (!(a.greaterEquals(b) > 0)) { a.addM(p); } a.subM(b); } x.halveM(); if ((a.limbs.get(0) & 1) > 0) { a.addM(p); } a.normalize(); a.halveM(); for (i = nz = 0; i < x.limbs.length; i++) { nz = (int) (nz | x.limbs.get(i)); } } while (nz > 0); if (!y.equals(1)) { throw new RuntimeException( "inverseMod: p and x must be relatively prime"); } return b; } public BigNumber mul(BigNumber that) { int i, j; LongArray a = this.limbs, b = that.limbs; int al = a.length, bl = b.length; BigNumber out = new BigNumber(); LongArray c = out.limbs; long ai, ii = this.maxMul; for (i = 0; i < this.limbs.length + that.limbs.length + 1; i++) { c.set(i, 0); } for (i = 0; i < al; i++) { ai = a.get(i); for (j = 0; j < bl; j++) { c.set(i + j, c.get(i + j) + ai * b.get(j)); } if (!(--ii > 0)) { ii = this.maxMul; out.cnormalize(); } } return out.cnormalize().reduce(); } public BigNumber square() { return this.mul(this); } public BigNumber power(BigNumber l) { LongArray nl = l.normalize().limbs; int i, j; BigNumber out = new BigNumber(BigNumber.ONE), pow = this; for (i = 0; i < nl.length; i++) { for (j = 0; j < this.radix; j++) { if ((nl.get(i) & (1 << j)) > 0) { out = out.mul(pow); } pow = pow.square(); } } return out; } public BigNumber reduce() { return this; } public BigNumber mulmod(BigNumber that, BigNumber N) { return this.mod(N).mul(that.mod(N)).mod(N); } public long bitLength() { this.fullReduce(); long out = this.radix * (this.limbs.length - 1), b = this.limbs .get(this.limbs.length - 1); for (; b > 0; b >>>= 1) { out++; } return out + 7 & -8; } public LongArray toBits() { return toBits(0); } public LongArray toBits(long len) { this.fullReduce(); len = JS.OR(JS.OR(len, this.exponent).longValue(), this.bitLength()) .longValue(); int i = (int) Math.floor((len - 1) / 24); long e = (len + 7 & -8) % JS.OR(this.radix, this.radix).longValue(); long c = BitArray.partial(e, this.getLimb(i), 0); LongArray out = new LongArray(new long[] { c }); for (i--; i >= 0; i--) { long a = BitArray.partial(Math.min(this.radix, len), this.getLimb(i)); long[] arrays = new long[] { a }; out = BitArray.concat(out, new LongArray(arrays)); len -= this.radix; } return out; } public int sign() { return this.greaterEquals(ZERO) > 0 ? 1 : -1; } public BigNumber shiftRight(long that) { that = +that; if (that < 0) { return this.shiftLeft(that); } BigNumber a = new BigNumber(this); while (that >= this.radix) { a.limbs.shift(); that -= this.radix; } while ((that--) > 0) { a.halveM(); } return a; } public BigNumber shiftLeft(long that) { that = +that; if (that < 0) { return shiftRight(that); } BigNumber a = new BigNumber(this); while (that >= this.radix) { a.limbs.unshift(0); that -= this.radix; } while ((that--) > 0) { a.doubleM(); } return a; } public long toNumber() { return this.limbs.get(0) | 0; } public long testBit(int bitIndex) { int limbIndex = (int) Math.floor((double) bitIndex / (double) this.radix); int bitIndexInLimb = (int) (bitIndex % this.radix); if (limbIndex >= this.limbs.length) { return 0; } return JS.MOVE_RightUShift(this.limbs.get(limbIndex), bitIndexInLimb) & 1; } public BigNumber setBitM(int bitIndex) { int limbIndex = (int) Math.floor(bitIndex / this.radix); int bitIndexInLimb = (int) (bitIndex % this.radix); while (limbIndex >= this.limbs.length) { this.limbs.push(0); } this.limbs.set(limbIndex, this.limbs.get(limbIndex) | 1 << bitIndexInLimb); this.cnormalize(); return this; } public int modInt(int n) { return (int) (this.toNumber() % n); } public int jacobi(BigNumber o) { BigNumber a = this; BigNumber that = new BigNumber(o); if (that.sign() == -1) { return -1; } if (a.equals(BigNumber.ZERO)) { return 0; } if (a.equals(BigNumber.ONE)) { return 1; } int s = 0; int e = 0; while (!(a.testBit(e) > 0)) { e++; } BigNumber a1 = a.shiftRight(e); if ((e & 1) == 0) { s = 1; } else { int residue = that.modInt(8); if (residue == 1 || residue == 7) { s = 1; } else if (residue == 3 || residue == 5) { s = -1; } } if (that.modInt(4) == 3 && a1.modInt(4) == 3) { s = -s; } if (a1.equals(BigNumber.ONE)) { return s; } else { return s * that.mod(a1).jacobi(a1); } } public BigNumber powermod(BigNumber x, BigNumber N) { BigNumber result = new BigNumber(1), a = new BigNumber(this), k = new BigNumber( x); for (;;) { if ((k.limbs.get(0) & 1) > 0) { result = result.mulmod(a, N); } k.halveM(); if (k.equals(0)) { break; } a = a.mulmod(a, N); } return result.normalize().reduce(); } public BigNumber fromBits(LongArray bits) { BigNumber out = new BigNumber(); LongArray words = new LongArray(); long l = Math.min(JS.OR(this.bitLength(), 0x100000000l).longValue(), BitArray.bitLength(bits)), e = l % JS.OR(radix, radix).longValue(); words.set(0, BitArray.extract(bits, 0, (int) e)); for (; e < l; e += radix) { words.unshift(BitArray.extract(bits, (int) e, (int) radix)); } out.limbs = words; return out; } public BigNumber cnormalize() { int i = 0; BigDecimal ipv = this.ipv; long carry = 0, l, m; LongArray limbs = this.limbs; int ll = limbs.length; long mask = this.radixMask; for (i = 0; i < ll - 1; i++) { l = limbs.items[i] + carry; m = limbs.items[i] = l & mask; carry = ipv.multiply(BigDecimal.valueOf((l - m))).longValue(); } limbs.set(i, limbs.get(i) + carry); return this; } public long getLimb(int i) { return (i >= this.limbs.length) ? 0 : this.limbs.get(i); } public BigNumber fullReduce() { return this.normalize(); } public long invDigit() { long radixMod = 1 + this.radixMask; if (this.limbs.length < 1) { return 0; } long x = this.limbs.get(0); if ((x & 1) == 0) { return 0; } long y = x & 3; y = (y * (2 - (x & 0xf) * y)) & 0xf; y = (y * (2 - (x & 0xff) * y)) & 0xff; y = (y * (2 - (((x & 0xffff) * y) & 0xffff))) & 0xffff; y = (y * (2 - x * y % radixMod)) % radixMod; return (y > 0) ? radixMod - y : -y; } public BigNumber neg() { return ZERO.sub(this); } public BigNumber abs() { if (this.sign() == -1) { return this.neg(); } else return this; } public long nbits(long x) { long r = 1, t; if ((t = JS.MOVE_RightUShift(x, 16)) != 0) { x = t; r += 16; } if ((t = x >> 8) != 0) { x = t; r += 8; } if ((t = x >> 4) != 0) { x = t; r += 4; } if ((t = x >> 2) != 0) { x = t; r += 2; } if ((t = x >> 1) != 0) { x = t; r += 1; } return r; } public long am(int i, long x, BigNumber w, int j, long c, long n) { long xl = x & 0xfff, xh = x >> 12; while (--n >= 0) { long l = this.limbs.get(i) & 0xfff; long h = this.limbs.get(i++) >> 12; long m = xh * l + h * xl; l = xl * l + ((m & 0xfff) << 12) + w.limbs.get(j) + c; c = (l >> 24) + (m >> 12) + xh * h; w.limbs.set(j++, (int) (l & 0xffffffl)); } return c; } public void initWith(Object it) { if (it == null) { this.limbs = new LongArray(); this.normalize(); return; } int i = 0, k; if (it instanceof BigNumber) { BigNumber its = (BigNumber) it; this.limbs = its.limbs.slice(0); } else if (it instanceof String) { String itStr = (String) it; if (itStr.startsWith("0x")) { itStr = itStr.substring(2, itStr.length()); } this.limbs = new LongArray(); k = (int) (this.radix / 4); for (i = 0; i < itStr.length(); i += k) { int v = Integer.parseInt( itStr.substring(Math.max(itStr.length() - i - k, 0), itStr.length() - i), 16); this.limbs.add(v); } } else if (it instanceof LongArray) { LongArray itArray = (LongArray) it; this.limbs = itArray.slice(0); } else if (it instanceof Number) { this.limbs = new LongArray(new long[] { ((Number) it).longValue() }); this.normalize(); } else if (it instanceof byte[]) { this.limbs = new LongArray(); byte[] buffer = (byte[]) it; ArrayByte ins = new ArrayByte(buffer); for (int j = 0; j < buffer.length; j += 4) { limbs.add(ins.readInt()); } ins.close(); this.normalize(); } else if (it instanceof ArrayByte) { this.limbs = new LongArray(); ArrayByte buffer = (ArrayByte) it; int c = -1; for (; (c = buffer.readByte()) != -1;) { limbs.add(c); } buffer.close(); this.normalize(); } else { this.limbs = new LongArray(new long[] { 0 }); } } public BigNumber powermodMontgomery(BigNumber e, BigNumber m) { long i = e.bitLength(), k = 0; BigNumber r = new BigNumber(BigNumber.ONE); if (i <= 0) { return r; } else if (i < 18) { k = 1; } else if (i < 48) { k = 3; } else if (i < 144) { k = 4; } else if (i < 768) { k = 5; } else { k = 6; } if (i < 8 || !(m.testBit(0) > 0)) { return this.powermod(e, m); } Montgomery z = new Montgomery(m); e.trim().normalize(); Array<BigNumber> g = new Array<BigNumber>(); long n = 3, k1 = (int) (k - 1), km = (1 << k) - 1; g.set(1, z.convert(this)); if (k > 1) { BigNumber g2 = z.square(g.get(1)); while (n <= km) { g.set((int) n, z.multiply(g2, g.get((int) n - 2))); n += 2; } } int j = e.limbs.length - 1; long w; boolean is1 = true; BigNumber r2 = new BigNumber(), t; i = nbits(e.limbs.get(j)) - 1; while (j >= 0) { if (i >= k1) w = (e.limbs.get(j) >> (i - k1)) & km; else { w = (e.limbs.get(j) & ((1 << (i + 1)) - 1)) << (k1 - i); if (j > 0) { w |= e.limbs.get(j - 1) >> (this.radix + i - k1); } } n = k; while ((w & 1) == 0) { w >>= 1; --n; } if ((i -= n) < 0) { i += this.radix; --j; } if (is1) { r = g.get((int) w).copy(); is1 = false; } else { while (n > 1) { r2 = z.square(r); r = z.square(r2); n -= 2; } if (n > 0) r2 = z.square(r); else { t = r; r = r2; r2 = t; } r = z.multiply(r2, g.get((int) w)); } while (j >= 0 && (e.limbs.get(j) & (1 << i)) == 0) { r2 = z.square(r); t = r; r = r2; r2 = t; if (--i < 0) { i = this.radix - 1; --j; } } } return z.revert(r); } static LongArray randomWords(int nwords, int paranoia) { LongArray out = new LongArray(); int i; for (i = 0; i < nwords; i += 4) { out.push(LSystem.random.nextInt()); out.push(LSystem.random.nextInt()); out.push(LSystem.random.nextInt()); out.push(LSystem.random.nextInt()); } return out.slice(0, nwords); } public static BigNumber random(BigNumber modulus, int paranoia) { LongArray words; int i, l = modulus.limbs.length; long m = modulus.limbs.get(l - 1) + 1; for (;;) { do { words = randomWords(l, paranoia); if (words.get(l - 1) < 0) { words.set(l - 1, (words.get(l - 1) + 0x100000000l)); } } while (Math.floor((double) words.get(l - 1) / (double) m) == (Math .floor((double) 0x100000000l / (double) m))); words.set(l - 1, ((words.get(l - 1) % m))); for (i = 0; i < l - 1; i++) { words.set(i, words.get(i) & modulus.radixMask); } BigNumber out = new BigNumber(words); if (!(out.greaterEquals(modulus) > 0)) { return out; } } } public static String hex_fromBits(LongArray arr) { String out = ""; int i; for (i = 0; i < arr.length; i++) { out += Long.toHexString(((int) (arr.get(i) | 0) + 0xF00000000000l)) .substring(4); } return out.substring(0, (int) BitArray.bitLength(arr) / 4); } public static LongArray hex_toBits(String str) { int i = 0; LongArray out = new LongArray(); int len; str = str.replace("0x", ""); len = str.length(); str = str + "00000000"; for (i = 0; i < str.length(); i += 8) { String res = str.substring(i, i + 8); out.push(new BigInteger(res, 16).intValue() ^ 0); } return BitArray.clamp(out, len * 4); } public static String utf8_fromBits(LongArray arr) { String out = ""; int i = 0; long bl = BitArray.bitLength(arr); long tmp = 0; for (i = 0; i < bl / 8; i++) { if ((i & 3) == 0) { tmp = arr.get(i / 4); } out += String.valueOf(JS.MOVE_LeftShift(tmp, 24)); tmp <<= 8; } return decodeURIComponent(JSEscape.escape(out)); } public static LongArray utf8_toBits(String str) { str = JSEscape.unescape(encodeURIComponent(str)); LongArray out = new LongArray(); int i, tmp = 0; for (i = 0; i < str.length(); i++) { tmp = tmp << 8 | str.charAt(i); if ((i & 3) == 3) { out.push(tmp); tmp = 0; } } if ((i & 3) > 0) { out.push(BitArray.partial(8 * (i & 3), tmp)); } return out; } public static LongArray bytes_fromBits(LongArray arr) { LongArray out = new LongArray(); long bl = BitArray.bitLength(arr); int i = 0; long tmp = 0; for (i = 0; i < bl / 8; i++) { if ((i & 3) == 0) { tmp = arr.get(i / 4); } out.push(JS.MOVE_RightUShift(tmp, 24)); tmp <<= 8; } return out; } public static LongArray bytes_toBits(byte[] bytes) { LongArray out = new LongArray(); int i = 0; long tmp = 0; for (i = 0; i < bytes.length; i++) { tmp = (int) (tmp << 8 | bytes[i]); if ((i & 3) == 3) { out.push(tmp); tmp = 0; } } if ((i & 3) > 0) { out.push(BitArray.partial(8 * (i & 3), tmp)); } return out; } public static String base64_fromBits(LongArray arr) { return base64_fromBits(arr, false, false); } public static String base64_fromBits(LongArray arr, boolean _noEquals, boolean _url) { String out = ""; int i, bits = 0; String c = base64_chars; long ta = 0, bl = BitArray.bitLength(arr); if (_url) { c = c.substring(0, 62) + "-_"; } for (i = 0; out.length() * 6 < bl;) { out += c.charAt((int) (JS.MOVE_RightUShift( (ta ^ JS.MOVE_RightUShift(arr.get(i), bits)), 26))); if (bits < 6) { ta = arr.get(i) << (6 - bits); bits += 26; i++; } else { ta <<= 6; bits -= 6; } } while (((out.length() & 3) > 0) && !_noEquals) { out += "="; } return out; } public static LongArray base64_toBits(String str) { return base64_toBits(str, false); } public static LongArray base64_toBits(String str, boolean _url) { str = str.replace("=", ""); LongArray out = new LongArray(); int i, bits = 0; String c = base64_chars; long ta = 0, x; if (_url) { c = c.substring(0, 62) + "-_"; } for (i = 0; i < str.length(); i++) { x = c.indexOf(str.charAt(i)); if (x < 0) { throw new RuntimeException("this isn't base64!"); } if (bits > 26) { bits -= 26; out.push(ta ^ JS.MOVE_RightUShift(x, bits)); ta = (int) (x << (32 - bits)); } else { bits += 6; ta ^= (int) (x << (32 - bits)); } } if ((bits & 56) > 0) { out.push(BitArray.partial(bits & 56, ta, 1)); } return out; } public static LongArray fdh(Object d, long bytelen) { LongArray data = null; if (d instanceof String) { data = utf8_toBits((String) d); } else if (d instanceof LongArray) { data = (LongArray) d; } long bitlen = bytelen << 3; int counter = 0; LongArray output = new LongArray(); while (BitArray.bitLength(output) < bitlen) { LongArray res = BitArray.concat(new LongArray( new long[] { counter }), data); LongArray hash = SHA512.hash(res); output = BitArray.concat(output, hash); counter++; } output = BitArray.clamp(output, bitlen); return output; } public static String signature(String secret, LongArray data) { HMAC hmac = new HMAC(hex_toBits(secret)); return hex_fromBits(hmac.mac(data)); } public static String hashSha512(LongArray data) { return hex_fromBits(SHA512.hash(data)); } public boolean isNegative() { return toNumber() < 0; } public boolean isPositive() { return toNumber() > -1; } public boolean isZero() { return toNumber() == 0; } }