| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE |
| * file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file |
| * to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the |
| * License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
| * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations under the License. |
| */ |
| package org.apache.tuweni.units.bigints; |
| |
| import static com.google.common.base.Preconditions.checkArgument; |
| |
| import org.apache.tuweni.bytes.Bytes; |
| import org.apache.tuweni.bytes.Bytes32; |
| import org.apache.tuweni.bytes.MutableBytes; |
| import org.apache.tuweni.bytes.MutableBytes32; |
| |
| import java.math.BigInteger; |
| import java.util.Arrays; |
| |
| /** |
| * An unsigned 256-bit precision number. |
| * |
| * This is a raw {@link UInt256Value} - a 256-bit precision unsigned number of no particular unit. |
| */ |
| public final class UInt256 implements UInt256Value<UInt256> { |
| private final static int MAX_CONSTANT = 64; |
| private final static BigInteger BI_MAX_CONSTANT = BigInteger.valueOf(MAX_CONSTANT); |
| private static UInt256[] CONSTANTS = new UInt256[MAX_CONSTANT + 1]; |
| static { |
| CONSTANTS[0] = new UInt256(Bytes32.ZERO); |
| for (int i = 1; i <= MAX_CONSTANT; ++i) { |
| CONSTANTS[i] = new UInt256(i); |
| } |
| } |
| |
| /** The minimum value of a UInt256 */ |
| public final static UInt256 MIN_VALUE = valueOf(0); |
| /** The maximum value of a UInt256 */ |
| public final static UInt256 MAX_VALUE = new UInt256(Bytes32.ZERO.not()); |
| /** The value 0 */ |
| public final static UInt256 ZERO = valueOf(0); |
| /** The value 1 */ |
| public final static UInt256 ONE = valueOf(1); |
| |
| private static final int INTS_SIZE = 32 / 4; |
| // The mask is used to obtain the value of an int as if it were unsigned. |
| private static final long LONG_MASK = 0xFFFFFFFFL; |
| private static final BigInteger P_2_256 = BigInteger.valueOf(2).pow(256); |
| |
| // The unsigned int components of the value |
| private final int[] ints; |
| |
| /** |
| * Return a {@code UInt256} containing the specified value. |
| * |
| * @param value The value to create a {@code UInt256} for. |
| * @return A {@code UInt256} containing the specified value. |
| * @throws IllegalArgumentException If the value is negative. |
| */ |
| public static UInt256 valueOf(long value) { |
| checkArgument(value >= 0, "Argument must be positive"); |
| if (value <= MAX_CONSTANT) { |
| return CONSTANTS[(int) value]; |
| } |
| return new UInt256(value); |
| } |
| |
| /** |
| * Return a {@link UInt256} containing the specified value. |
| * |
| * @param value the value to create a {@link UInt256} for |
| * @return a {@link UInt256} containing the specified value |
| * @throws IllegalArgumentException if the value is negative or too large to be represented as a UInt256 |
| */ |
| public static UInt256 valueOf(BigInteger value) { |
| checkArgument(value.signum() >= 0, "Argument must be positive"); |
| checkArgument(value.bitLength() <= 256, "Argument is too large to represent a UInt256"); |
| if (value.compareTo(BI_MAX_CONSTANT) <= 0) { |
| return CONSTANTS[value.intValue()]; |
| } |
| int[] ints = new int[INTS_SIZE]; |
| for (int i = INTS_SIZE - 1; i >= 0; --i) { |
| ints[i] = value.intValue(); |
| value = value.shiftRight(32); |
| } |
| return new UInt256(ints); |
| } |
| |
| /** |
| * Return a {@link UInt256} containing the value described by the specified bytes. |
| * |
| * @param bytes The bytes containing a {@link UInt256}. |
| * @return A {@link UInt256} containing the specified value. |
| * @throws IllegalArgumentException if {@code bytes.size() > 32}. |
| */ |
| public static UInt256 fromBytes(Bytes bytes) { |
| return new UInt256(Bytes32.leftPad(bytes)); |
| } |
| |
| /** |
| * Parse a hexadecimal string into a {@link UInt256}. |
| * |
| * @param str The hexadecimal string to parse, which may or may not start with "0x". That representation may contain |
| * less than 32 bytes, in which case the result is left padded with zeros. |
| * @return The value corresponding to {@code str}. |
| * @throws IllegalArgumentException if {@code str} does not correspond to a valid hexadecimal representation or |
| * contains more than 32 bytes. |
| */ |
| public static UInt256 fromHexString(String str) { |
| return new UInt256(Bytes32.fromHexStringLenient(str)); |
| } |
| |
| private UInt256(Bytes32 bytes) { |
| this.ints = new int[INTS_SIZE]; |
| for (int i = 0, j = 0; i < INTS_SIZE; ++i, j += 4) { |
| ints[i] = bytes.getInt(j); |
| } |
| } |
| |
| private UInt256(long value) { |
| this.ints = new int[INTS_SIZE]; |
| this.ints[INTS_SIZE - 2] = (int) ((value >>> 32) & LONG_MASK); |
| this.ints[INTS_SIZE - 1] = (int) (value & LONG_MASK); |
| } |
| |
| private UInt256(int[] ints) { |
| this.ints = ints; |
| } |
| |
| @SuppressWarnings("ReferenceEquality") |
| @Override |
| public boolean isZero() { |
| if (this == ZERO) { |
| return true; |
| } |
| for (int i = INTS_SIZE - 1; i >= 0; --i) { |
| if (this.ints[i] != 0) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| @Override |
| public UInt256 add(UInt256 value) { |
| if (value.isZero()) { |
| return this; |
| } |
| if (isZero()) { |
| return value; |
| } |
| int[] result = new int[INTS_SIZE]; |
| boolean constant = true; |
| long sum = (this.ints[INTS_SIZE - 1] & LONG_MASK) + (value.ints[INTS_SIZE - 1] & LONG_MASK); |
| result[INTS_SIZE - 1] = (int) (sum & LONG_MASK); |
| if (result[INTS_SIZE - 1] < 0 || result[INTS_SIZE - 1] > MAX_CONSTANT) { |
| constant = false; |
| } |
| for (int i = INTS_SIZE - 2; i >= 0; --i) { |
| sum = (this.ints[i] & LONG_MASK) + (value.ints[i] & LONG_MASK) + (sum >>> 32); |
| result[i] = (int) (sum & LONG_MASK); |
| constant &= result[i] == 0; |
| } |
| if (constant) { |
| return CONSTANTS[result[INTS_SIZE - 1]]; |
| } |
| return new UInt256(result); |
| } |
| |
| @Override |
| public UInt256 add(long value) { |
| if (value == 0) { |
| return this; |
| } |
| if (value > 0 && isZero()) { |
| return UInt256.valueOf(value); |
| } |
| int[] result = new int[INTS_SIZE]; |
| boolean constant = true; |
| long sum = (this.ints[INTS_SIZE - 1] & LONG_MASK) + (value & LONG_MASK); |
| result[INTS_SIZE - 1] = (int) (sum & LONG_MASK); |
| if (result[INTS_SIZE - 1] < 0 || result[INTS_SIZE - 1] > MAX_CONSTANT) { |
| constant = false; |
| } |
| sum = (this.ints[INTS_SIZE - 2] & LONG_MASK) + (value >>> 32) + (sum >>> 32); |
| result[INTS_SIZE - 2] = (int) (sum & LONG_MASK); |
| constant &= result[INTS_SIZE - 2] == 0; |
| long signExtent = (value >> 63) & LONG_MASK; |
| for (int i = INTS_SIZE - 2; i >= 0; --i) { |
| sum = (this.ints[i] & LONG_MASK) + signExtent + (sum >>> 32); |
| result[i] = (int) (sum & LONG_MASK); |
| constant &= result[i] == 0; |
| } |
| if (constant) { |
| return CONSTANTS[result[INTS_SIZE - 1]]; |
| } |
| return new UInt256(result); |
| } |
| |
| @Override |
| public UInt256 addMod(UInt256 value, UInt256 modulus) { |
| if (modulus.isZero()) { |
| throw new ArithmeticException("addMod with zero modulus"); |
| } |
| return UInt256.valueOf(toBigInteger().add(value.toBigInteger()).mod(modulus.toBigInteger())); |
| } |
| |
| @Override |
| public UInt256 addMod(long value, UInt256 modulus) { |
| if (modulus.isZero()) { |
| throw new ArithmeticException("addMod with zero modulus"); |
| } |
| return UInt256.valueOf(toBigInteger().add(BigInteger.valueOf(value)).mod(modulus.toBigInteger())); |
| } |
| |
| @Override |
| public UInt256 addMod(long value, long modulus) { |
| if (modulus == 0) { |
| throw new ArithmeticException("addMod with zero modulus"); |
| } |
| if (modulus < 0) { |
| throw new ArithmeticException("addMod unsigned with negative modulus"); |
| } |
| return UInt256.valueOf(toBigInteger().add(BigInteger.valueOf(value)).mod(BigInteger.valueOf(modulus))); |
| } |
| |
| @Override |
| public UInt256 subtract(UInt256 value) { |
| if (value.isZero()) { |
| return this; |
| } |
| |
| int[] result = new int[INTS_SIZE]; |
| boolean constant = true; |
| long sum = (this.ints[INTS_SIZE - 1] & LONG_MASK) + ((~value.ints[INTS_SIZE - 1]) & LONG_MASK) + 1; |
| result[INTS_SIZE - 1] = (int) (sum & LONG_MASK); |
| if (result[INTS_SIZE - 1] < 0 || result[INTS_SIZE - 1] > MAX_CONSTANT) { |
| constant = false; |
| } |
| for (int i = INTS_SIZE - 2; i >= 0; --i) { |
| sum = (this.ints[i] & LONG_MASK) + ((~value.ints[i]) & LONG_MASK) + (sum >>> 32); |
| result[i] = (int) (sum & LONG_MASK); |
| constant &= result[i] == 0; |
| } |
| if (constant) { |
| return CONSTANTS[result[INTS_SIZE - 1]]; |
| } |
| return new UInt256(result); |
| } |
| |
| @Override |
| public UInt256 subtract(long value) { |
| return add(-value); |
| } |
| |
| @Override |
| public UInt256 multiply(UInt256 value) { |
| if (isZero() || value.isZero()) { |
| return ZERO; |
| } |
| if (value.equals(UInt256.ONE)) { |
| return this; |
| } |
| if (this.equals(UInt256.ONE)) { |
| return value; |
| } |
| return multiply(this.ints, value.ints); |
| } |
| |
| private static UInt256 multiply(int[] x, int[] y) { |
| int[] result = new int[INTS_SIZE + INTS_SIZE]; |
| |
| long carry = 0; |
| for (int j = INTS_SIZE - 1, k = INTS_SIZE + INTS_SIZE - 1; j >= 0; j--, k--) { |
| long product = (y[j] & LONG_MASK) * (x[INTS_SIZE - 1] & LONG_MASK) + carry; |
| result[k] = (int) product; |
| carry = product >>> 32; |
| } |
| result[INTS_SIZE - 1] = (int) carry; |
| |
| for (int i = INTS_SIZE - 2; i >= 0; i--) { |
| carry = 0; |
| for (int j = INTS_SIZE - 1, k = INTS_SIZE + i; j >= 0; j--, k--) { |
| long product = (y[j] & LONG_MASK) * (x[i] & LONG_MASK) + (result[k] & LONG_MASK) + carry; |
| |
| result[k] = (int) product; |
| carry = product >>> 32; |
| } |
| result[i] = (int) carry; |
| } |
| |
| boolean constant = true; |
| for (int i = INTS_SIZE; i < (INTS_SIZE + INTS_SIZE) - 1; ++i) { |
| constant &= (result[i] == 0); |
| } |
| if (constant && result[INTS_SIZE + INTS_SIZE - 1] >= 0 && result[INTS_SIZE + INTS_SIZE - 1] <= MAX_CONSTANT) { |
| return CONSTANTS[result[INTS_SIZE + INTS_SIZE - 1]]; |
| } |
| return new UInt256(Arrays.copyOfRange(result, INTS_SIZE, INTS_SIZE + INTS_SIZE)); |
| } |
| |
| @Override |
| public UInt256 multiply(long value) { |
| if (value == 0 || isZero()) { |
| return ZERO; |
| } |
| if (value == 1) { |
| return this; |
| } |
| if (value < 0) { |
| throw new ArithmeticException("multiply unsigned by negative"); |
| } |
| UInt256 other = new UInt256(value); |
| if (this.equals(UInt256.ONE)) { |
| return other; |
| } |
| return multiply(this.ints, other.ints); |
| } |
| |
| @Override |
| public UInt256 multiplyMod(UInt256 value, UInt256 modulus) { |
| if (modulus.isZero()) { |
| throw new ArithmeticException("multiplyMod with zero modulus"); |
| } |
| if (isZero() || value.isZero()) { |
| return ZERO; |
| } |
| if (value.equals(UInt256.ONE)) { |
| return mod(modulus); |
| } |
| return UInt256.valueOf(toBigInteger().multiply(value.toBigInteger()).mod(modulus.toBigInteger())); |
| } |
| |
| @Override |
| public UInt256 multiplyMod(long value, UInt256 modulus) { |
| if (modulus.isZero()) { |
| throw new ArithmeticException("multiplyMod with zero modulus"); |
| } |
| if (value == 0 || isZero()) { |
| return ZERO; |
| } |
| if (value == 1) { |
| return mod(modulus); |
| } |
| if (value < 0) { |
| throw new ArithmeticException("multiplyMod unsigned by negative"); |
| } |
| return UInt256.valueOf(toBigInteger().multiply(BigInteger.valueOf(value)).mod(modulus.toBigInteger())); |
| } |
| |
| @Override |
| public UInt256 multiplyMod(long value, long modulus) { |
| if (modulus == 0) { |
| throw new ArithmeticException("multiplyMod with zero modulus"); |
| } |
| if (modulus < 0) { |
| throw new ArithmeticException("multiplyMod unsigned with negative modulus"); |
| } |
| if (value == 0 || isZero()) { |
| return ZERO; |
| } |
| if (value == 1) { |
| return mod(modulus); |
| } |
| if (value < 0) { |
| throw new ArithmeticException("multiplyMod unsigned by negative"); |
| } |
| return UInt256.valueOf(toBigInteger().multiply(BigInteger.valueOf(value)).mod(BigInteger.valueOf(modulus))); |
| } |
| |
| @Override |
| public UInt256 divide(UInt256 value) { |
| if (value.isZero()) { |
| throw new ArithmeticException("divide by zero"); |
| } |
| if (value.equals(UInt256.ONE)) { |
| return this; |
| } |
| return UInt256.valueOf(toBigInteger().divide(value.toBigInteger())); |
| } |
| |
| @Override |
| public UInt256 divide(long value) { |
| if (value == 0) { |
| throw new ArithmeticException("divide by zero"); |
| } |
| if (value < 0) { |
| throw new ArithmeticException("divide unsigned by negative"); |
| } |
| if (value == 1) { |
| return this; |
| } |
| if (isPowerOf2(value)) { |
| return shiftRight(log2(value)); |
| } |
| return UInt256.valueOf(toBigInteger().divide(BigInteger.valueOf(value))); |
| } |
| |
| @Override |
| public UInt256 divideCeil(UInt256 value) { |
| return this.divide(value).add(this.mod(value).isZero() ? 0 : 1); |
| } |
| |
| @Override |
| public UInt256 divideCeil(long value) { |
| return this.divide(value).add(this.mod(value).isZero() ? 0 : 1); |
| } |
| |
| @Override |
| public UInt256 pow(UInt256 exponent) { |
| return UInt256.valueOf(toBigInteger().modPow(exponent.toBigInteger(), P_2_256)); |
| } |
| |
| @Override |
| public UInt256 pow(long exponent) { |
| return UInt256.valueOf(toBigInteger().modPow(BigInteger.valueOf(exponent), P_2_256)); |
| } |
| |
| @Override |
| public UInt256 mod(UInt256 modulus) { |
| if (modulus.isZero()) { |
| throw new ArithmeticException("mod by zero"); |
| } |
| return UInt256.valueOf(toBigInteger().mod(modulus.toBigInteger())); |
| } |
| |
| @Override |
| public UInt256 mod(long modulus) { |
| if (modulus == 0) { |
| throw new ArithmeticException("mod by zero"); |
| } |
| if (modulus < 0) { |
| throw new ArithmeticException("mod by negative"); |
| } |
| if (isPowerOf2(modulus)) { |
| int log2 = log2(modulus); |
| int d = log2 / 32; |
| int s = log2 % 32; |
| assert (d == 0 || d == 1); |
| |
| int[] result = new int[INTS_SIZE]; |
| // Mask the byte at d to only include the s right-most bits |
| result[INTS_SIZE - 1 - d] = this.ints[INTS_SIZE - 1 - d] & ~(0xFFFFFFFF << s); |
| if (d != 0) { |
| result[INTS_SIZE - 1] = this.ints[INTS_SIZE - 1]; |
| } |
| return new UInt256(result); |
| } |
| return UInt256.valueOf(toBigInteger().mod(BigInteger.valueOf(modulus))); |
| } |
| |
| @Override |
| public UInt256 mod0(UInt256 modulus) { |
| if (modulus.equals(UInt256.ZERO)) { |
| return UInt256.ZERO; |
| } |
| return mod(modulus); |
| } |
| |
| @Override |
| public UInt256 mod0(long modulus) { |
| if (modulus == 0) { |
| return UInt256.ZERO; |
| } |
| if (modulus < 0) { |
| throw new ArithmeticException("mod by negative"); |
| } |
| return mod(modulus); |
| } |
| |
| /** |
| * Return a bit-wise AND of this value and the supplied value. |
| * |
| * @param value the value to perform the operation with |
| * @return the result of a bit-wise AND |
| */ |
| public UInt256 and(UInt256 value) { |
| int[] result = new int[INTS_SIZE]; |
| for (int i = INTS_SIZE - 1; i >= 0; --i) { |
| result[i] = this.ints[i] & value.ints[i]; |
| } |
| return new UInt256(result); |
| } |
| |
| /** |
| * Return a bit-wise AND of this value and the supplied bytes. |
| * |
| * @param bytes the bytes to perform the operation with |
| * @return the result of a bit-wise AND |
| */ |
| public UInt256 and(Bytes32 bytes) { |
| int[] result = new int[INTS_SIZE]; |
| for (int i = INTS_SIZE - 1, j = 28; i >= 0; --i, j -= 4) { |
| int other = ((int) bytes.get(j) & 0xFF) << 24; |
| other |= ((int) bytes.get(j + 1) & 0xFF) << 16; |
| other |= ((int) bytes.get(i + 2) & 0xFF) << 8; |
| other |= ((int) bytes.get(i + 3) & 0xFF); |
| result[i] = this.ints[i] & other; |
| } |
| return new UInt256(result); |
| } |
| |
| /** |
| * Return a bit-wise OR of this value and the supplied value. |
| * |
| * @param value the value to perform the operation with |
| * @return the result of a bit-wise OR |
| */ |
| public UInt256 or(UInt256 value) { |
| int[] result = new int[INTS_SIZE]; |
| for (int i = INTS_SIZE - 1; i >= 0; --i) { |
| result[i] = this.ints[i] | value.ints[i]; |
| } |
| return new UInt256(result); |
| } |
| |
| /** |
| * Return a bit-wise OR of this value and the supplied bytes. |
| * |
| * @param bytes the bytes to perform the operation with |
| * @return the result of a bit-wise OR |
| */ |
| public UInt256 or(Bytes32 bytes) { |
| int[] result = new int[INTS_SIZE]; |
| for (int i = INTS_SIZE - 1, j = 28; i >= 0; --i, j -= 4) { |
| result[i] = this.ints[i] | (((int) bytes.get(j) & 0xFF) << 24); |
| result[i] |= ((int) bytes.get(j + 1) & 0xFF) << 16; |
| result[i] |= ((int) bytes.get(j + 2) & 0xFF) << 8; |
| result[i] |= ((int) bytes.get(j + 3) & 0xFF); |
| } |
| return new UInt256(result); |
| } |
| |
| /** |
| * Return a bit-wise XOR of this value and the supplied value. |
| * |
| * @param value the value to perform the operation with |
| * @return the result of a bit-wise XOR |
| */ |
| public UInt256 xor(UInt256 value) { |
| int[] result = new int[INTS_SIZE]; |
| for (int i = INTS_SIZE - 1; i >= 0; --i) { |
| result[i] = this.ints[i] ^ value.ints[i]; |
| } |
| return new UInt256(result); |
| } |
| |
| /** |
| * Return a bit-wise XOR of this value and the supplied bytes. |
| * |
| * @param bytes the bytes to perform the operation with |
| * @return the result of a bit-wise XOR |
| */ |
| public UInt256 xor(Bytes32 bytes) { |
| int[] result = new int[INTS_SIZE]; |
| for (int i = INTS_SIZE - 1, j = 28; i >= 0; --i, j -= 4) { |
| result[i] = this.ints[i] ^ (((int) bytes.get(j) & 0xFF) << 24); |
| result[i] ^= ((int) bytes.get(j + 1) & 0xFF) << 16; |
| result[i] ^= ((int) bytes.get(j + 2) & 0xFF) << 8; |
| result[i] ^= ((int) bytes.get(j + 3) & 0xFF); |
| } |
| return new UInt256(result); |
| } |
| |
| /** |
| * Return a bit-wise NOT of this value. |
| * |
| * @return the result of a bit-wise NOT |
| */ |
| public UInt256 not() { |
| int[] result = new int[INTS_SIZE]; |
| for (int i = INTS_SIZE - 1; i >= 0; --i) { |
| result[i] = ~(this.ints[i]); |
| } |
| return new UInt256(result); |
| } |
| |
| /** |
| * Shift all bits in this value to the right. |
| * |
| * @param distance The number of bits to shift by. |
| * @return A value containing the shifted bits. |
| */ |
| public UInt256 shiftRight(int distance) { |
| if (distance == 0) { |
| return this; |
| } |
| if (distance >= 256) { |
| return ZERO; |
| } |
| int[] result = new int[INTS_SIZE]; |
| int d = distance / 32; |
| int s = distance % 32; |
| |
| int resIdx = INTS_SIZE; |
| if (s == 0) { |
| for (int i = INTS_SIZE - d; i > 0;) { |
| result[--resIdx] = this.ints[--i]; |
| } |
| } else { |
| for (int i = INTS_SIZE - 1 - d; i >= 0; i--) { |
| int leftSide = this.ints[i] >>> s; |
| int rightSide = (i == 0) ? 0 : this.ints[i - 1] << (32 - s); |
| result[--resIdx] = (leftSide | rightSide); |
| } |
| } |
| return new UInt256(result); |
| } |
| |
| /** |
| * Shift all bits in this value to the left. |
| * |
| * @param distance The number of bits to shift by. |
| * @return A value containing the shifted bits. |
| */ |
| public UInt256 shiftLeft(int distance) { |
| if (distance == 0) { |
| return this; |
| } |
| if (distance >= 256) { |
| return ZERO; |
| } |
| int[] result = new int[INTS_SIZE]; |
| int d = distance / 32; |
| int s = distance % 32; |
| |
| int resIdx = 0; |
| if (s == 0) { |
| for (int i = d; i < INTS_SIZE;) { |
| result[resIdx++] = this.ints[i++]; |
| } |
| } else { |
| for (int i = d; i < INTS_SIZE; ++i) { |
| int leftSide = this.ints[i] << s; |
| int rightSide = (i == INTS_SIZE - 1) ? 0 : (this.ints[i + 1] >>> (32 - s)); |
| result[resIdx++] = (leftSide | rightSide); |
| } |
| } |
| return new UInt256(result); |
| } |
| |
| @Override |
| public boolean equals(Object object) { |
| if (object == this) { |
| return true; |
| } |
| if (!(object instanceof UInt256)) { |
| return false; |
| } |
| UInt256 other = (UInt256) object; |
| for (int i = 0; i < INTS_SIZE; ++i) { |
| if (this.ints[i] != other.ints[i]) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| @Override |
| public int hashCode() { |
| int result = 1; |
| for (int i = 0; i < INTS_SIZE; ++i) { |
| result = 31 * result + this.ints[i]; |
| } |
| return result; |
| } |
| |
| @Override |
| public int compareTo(UInt256 other) { |
| for (int i = 0; i < INTS_SIZE; ++i) { |
| int cmp = Long.compare(((long) this.ints[i]) & LONG_MASK, ((long) other.ints[i]) & LONG_MASK); |
| if (cmp != 0) { |
| return cmp; |
| } |
| } |
| return 0; |
| } |
| |
| @Override |
| public boolean fitsInt() { |
| for (int i = 0; i < INTS_SIZE - 1; i++) { |
| if (this.ints[i] != 0) { |
| return false; |
| } |
| } |
| // Lastly, the left-most byte of the int must not start with a 1. |
| return this.ints[INTS_SIZE - 1] >= 0; |
| } |
| |
| @Override |
| public int intValue() { |
| if (!fitsInt()) { |
| throw new ArithmeticException("Value does not fit a 4 byte int"); |
| } |
| return this.ints[INTS_SIZE - 1]; |
| } |
| |
| @Override |
| public boolean fitsLong() { |
| for (int i = 0; i < INTS_SIZE - 2; i++) { |
| if (this.ints[i] != 0) { |
| return false; |
| } |
| } |
| // Lastly, the left-most byte of the int must not start with a 1. |
| return this.ints[INTS_SIZE - 2] >= 0; |
| } |
| |
| @Override |
| public long toLong() { |
| if (!fitsLong()) { |
| throw new ArithmeticException("Value does not fit a 8 byte long"); |
| } |
| return (((long) this.ints[INTS_SIZE - 2]) << 32) | (((long) (this.ints[INTS_SIZE - 1])) & LONG_MASK); |
| } |
| |
| @Override |
| public String toString() { |
| return toBigInteger().toString(); |
| } |
| |
| @Override |
| public BigInteger toBigInteger() { |
| byte[] mag = new byte[32]; |
| for (int i = 0, j = 0; i < INTS_SIZE; ++i) { |
| mag[j++] = (byte) (this.ints[i] >>> 24); |
| mag[j++] = (byte) ((this.ints[i] >>> 16) & 0xFF); |
| mag[j++] = (byte) ((this.ints[i] >>> 8) & 0xFF); |
| mag[j++] = (byte) (this.ints[i] & 0xFF); |
| } |
| return new BigInteger(1, mag); |
| } |
| |
| @Override |
| public UInt256 toUInt256() { |
| return this; |
| } |
| |
| @Override |
| public Bytes32 toBytes() { |
| MutableBytes32 bytes = MutableBytes32.create(); |
| for (int i = 0, j = 0; i < INTS_SIZE; ++i, j += 4) { |
| bytes.setInt(j, this.ints[i]); |
| } |
| return bytes; |
| } |
| |
| @Override |
| public Bytes toMinimalBytes() { |
| int i = 0; |
| while (i < INTS_SIZE && this.ints[i] == 0) { |
| ++i; |
| } |
| if (i == INTS_SIZE) { |
| return Bytes.EMPTY; |
| } |
| int firstIntBytes = 4 - (Integer.numberOfLeadingZeros(this.ints[i]) / 8); |
| int totalBytes = firstIntBytes + ((INTS_SIZE - (i + 1)) * 4); |
| MutableBytes bytes = MutableBytes.create(totalBytes); |
| int j = 0; |
| switch (firstIntBytes) { |
| case 4: |
| bytes.set(j++, (byte) (this.ints[i] >>> 24)); |
| // fall through |
| case 3: |
| bytes.set(j++, (byte) ((this.ints[i] >>> 16) & 0xFF)); |
| // fall through |
| case 2: |
| bytes.set(j++, (byte) ((this.ints[i] >>> 8) & 0xFF)); |
| // fall through |
| case 1: |
| bytes.set(j++, (byte) (this.ints[i] & 0xFF)); |
| } |
| ++i; |
| for (; i < INTS_SIZE; ++i, j += 4) { |
| bytes.setInt(j, this.ints[i]); |
| } |
| return bytes; |
| } |
| |
| @Override |
| public int numberOfLeadingZeros() { |
| for (int i = 0; i < INTS_SIZE; i++) { |
| if (this.ints[i] == 0) { |
| continue; |
| } |
| return (i * 32) + Integer.numberOfLeadingZeros(this.ints[i]); |
| } |
| return 256; |
| } |
| |
| @Override |
| public int bitLength() { |
| for (int i = 0; i < INTS_SIZE; i++) { |
| if (this.ints[i] == 0) { |
| continue; |
| } |
| return (INTS_SIZE * 32) - (i * 32) - Integer.numberOfLeadingZeros(this.ints[i]); |
| } |
| return 0; |
| } |
| |
| private static boolean isPowerOf2(long n) { |
| assert n > 0; |
| return (n & (n - 1)) == 0; |
| } |
| |
| private static int log2(long v) { |
| assert v > 0; |
| return 63 - Long.numberOfLeadingZeros(v); |
| } |
| } |