1414 */
1515package org .hyperledger .besu .evm ;
1616
17+ import java .util .Arrays ;
18+
1719/**
1820 * 256-bits wide unsigned integer class.
1921 *
@@ -141,6 +143,45 @@ public static UInt256 fromBytesBE(final byte[] bytes) {
141143 return new UInt256 (limbs , len );
142144 }
143145
146+ /**
147+ * Instantiates a new UInt256 from byte[].
148+ *
149+ * @param bytes raw bytes in BigEndian order.
150+ * @return Big-endian UInt256 represented by the bytes.
151+ */
152+ public static UInt256 fromSignedBytesBE (final byte [] bytes ) {
153+ int nBytes = bytes .length ;
154+ if (nBytes == 0 ) return ZERO ;
155+ int len = (nBytes + 3 ) / 4 ;
156+ int [] limbs = new int [len ];
157+ // int[] limbs = new int[N_LIMBS];
158+
159+ int i ;
160+ int base ;
161+ // Up to most significant limb take 4 bytes.
162+ for (i = 0 , base = bytes .length - 4 ; i < len - 1 ; ++i , base = base - 4 ) {
163+ limbs [i ] =
164+ (bytes [base ] << 24 )
165+ | ((bytes [base + 1 ] & 0xFF ) << 16 )
166+ | ((bytes [base + 2 ] & 0xFF ) << 8 )
167+ | ((bytes [base + 3 ] & 0xFF ));
168+ }
169+ // Last effective limb
170+ limbs [i ] =
171+ switch (nBytes - i * 4 ) {
172+ case 1 -> ((bytes [0 ]));
173+ case 2 -> (((bytes [0 ]) << 8 ) | (bytes [1 ] & 0xFF ));
174+ case 3 -> (((bytes [0 ]) << 16 ) | ((bytes [1 ] & 0xFF ) << 8 ) | (bytes [2 ] & 0xFF ));
175+ case 4 ->
176+ ((bytes [0 ] << 24 )
177+ | ((bytes [1 ] & 0xFF ) << 16 )
178+ | ((bytes [2 ] & 0xFF ) << 8 )
179+ | (bytes [3 ] & 0xFF ));
180+ default -> throw new IllegalStateException ("Unexpected value" );
181+ };
182+ return new UInt256 (limbs , len );
183+ }
184+
144185 /**
145186 * Instantiates a new UInt256 from an int.
146187 *
@@ -168,7 +209,6 @@ public static UInt256 fromLong(final long value) {
168209
169210 // region Conversions
170211 // --------------------------------------------------------------------------
171-
172212 /**
173213 * Convert to int.
174214 *
@@ -214,6 +254,43 @@ public byte[] toBytesBE() {
214254 return out ;
215255 }
216256
257+ /**
258+ * Convert to BigEndian byte array.
259+ *
260+ * @return Big-endian ordered bytes for this UInt256 value.
261+ */
262+ public byte [] toSignedBytesBE () {
263+ byte [] out = new byte [32 ];
264+ if (length > 0 && limbs [length - 1 ] < 0 ) Arrays .fill (out , (byte ) 0xFF );
265+ for (int i = 0 , offset = 28 ; i < length ; i ++, offset -= 4 ) {
266+ int v = limbs [i ];
267+ out [offset ] = (byte ) (v >>> 24 );
268+ out [offset + 1 ] = (byte ) (v >>> 16 );
269+ out [offset + 2 ] = (byte ) (v >>> 8 );
270+ out [offset + 3 ] = (byte ) v ;
271+ }
272+ return out ;
273+ }
274+
275+ /**
276+ * Convert to BigEndian byte array.
277+ *
278+ * @param sign if sign is negative, pad with 1s, else pad with 0s.
279+ * @return Big-endian ordered bytes for this UInt256 value.
280+ */
281+ public byte [] toSignedBytesBE (final int sign ) {
282+ byte [] out = new byte [32 ];
283+ if (sign < 0 ) Arrays .fill (out , (byte ) 0xFF );
284+ for (int i = 0 , offset = 28 ; i < length ; i ++, offset -= 4 ) {
285+ int v = limbs [i ];
286+ out [offset ] = (byte ) (v >>> 24 );
287+ out [offset + 1 ] = (byte ) (v >>> 16 );
288+ out [offset + 2 ] = (byte ) (v >>> 8 );
289+ out [offset + 3 ] = (byte ) v ;
290+ }
291+ return out ;
292+ }
293+
217294 @ Override
218295 public String toString () {
219296 StringBuilder sb = new StringBuilder ("0x" );
@@ -231,6 +308,33 @@ public String toString() {
231308 return sb .toString ();
232309 }
233310
311+ /**
312+ * Convert to hexstring according to sign.
313+ *
314+ * <p>If sign is negative, pad with 1s, else pad with 0s.
315+ * </p>
316+ *
317+ * @param sign padding with 0s or 1s whether sign is non-negative.
318+ * @return HexString
319+ */
320+ public String toString (final int sign ) {
321+ if (sign >= 0 ) return toString ();
322+ StringBuilder sb = new StringBuilder ("0x" );
323+ byte [] out = new byte [length * 4 ];
324+ Arrays .fill (out , (byte ) 0xFF );
325+ for (int i = 0 , offset = 4 * (length - 1 ); i < length ; i ++, offset -= 4 ) {
326+ int v = limbs [i ];
327+ out [offset ] = (byte ) (v >>> 24 );
328+ out [offset + 1 ] = (byte ) (v >>> 16 );
329+ out [offset + 2 ] = (byte ) (v >>> 8 );
330+ out [offset + 3 ] = (byte ) v ;
331+ }
332+ for (byte b : out ) {
333+ sb .append (String .format ("%02x" , b ));
334+ }
335+ return sb .toString ();
336+ }
337+
234338 // --------------------------------------------------------------------------
235339 // endregion
236340
@@ -330,6 +434,17 @@ public UInt256 shiftRight(final int shift) {
330434 // region Arithmetic Operations
331435 // --------------------------------------------------------------------------
332436
437+ /**
438+ * (Signed) absolute value
439+ *
440+ * @return The absolute value of this signed integer.
441+ */
442+ public UInt256 abs () {
443+ int [] newLimbs = Arrays .copyOf (limbs , length );
444+ absInplace (newLimbs );
445+ return new UInt256 (newLimbs , length );
446+ }
447+
333448 /**
334449 * Addition (modulo 2**256).
335450 *
@@ -356,7 +471,7 @@ public UInt256 mul(final UInt256 other) {
356471 }
357472
358473 /**
359- * Reduce modulo modulus .
474+ * Unsigned modulo reduction .
360475 *
361476 * @param modulus The modulus of the reduction
362477 * @return The remainder modulo {@code modulus}.
@@ -368,6 +483,28 @@ public UInt256 mod(final UInt256 modulus) {
368483 return new UInt256 (knuthRemainder (this .limbs , modulus .limbs ));
369484 }
370485
486+ /**
487+ * Signed modulo reduction.
488+ *
489+ * @param modulus The modulus of the reduction
490+ * @return The remainder modulo {@code modulus}.
491+ */
492+ public UInt256 signedMod (final UInt256 modulus ) {
493+ if (this .isZero () || modulus .isZero ()) return ZERO ;
494+ int [] x = new int [this .length ];
495+ int [] y = new int [modulus .length ];
496+ absInto (x , this .limbs );
497+ absInto (y , modulus .limbs );
498+ int [] r = knuthRemainder (x , y );
499+ if (isNegative (this .limbs )) {
500+ int [] s = new int [N_LIMBS ];
501+ System .arraycopy (r , 0 , s , 0 , r .length );
502+ negate (s );
503+ return new UInt256 (s );
504+ }
505+ return new UInt256 (r );
506+ }
507+
371508 /**
372509 * Modular addition.
373510 *
@@ -404,6 +541,27 @@ public UInt256 mulMod(final UInt256 other, final UInt256 modulus) {
404541
405542 // region Support (private) Algorithms
406543 // --------------------------------------------------------------------------
544+ private static boolean isNegative (final int [] x ) {
545+ return x [x .length - 1 ] < 0 ;
546+ }
547+
548+ private static void negate (final int [] x ) {
549+ int carry = 1 ;
550+ for (int i = 0 ; i < x .length ; i ++) {
551+ x [i ] = ~x [i ] + carry ;
552+ carry = (x [i ] == 0 && carry == 1 ) ? 1 : 0 ;
553+ }
554+ }
555+
556+ private static void absInplace (final int [] x ) {
557+ if (isNegative (x )) negate (x );
558+ }
559+
560+ private static void absInto (final int [] dst , final int [] src ) {
561+ System .arraycopy (src , 0 , dst , 0 , Math .min (dst .length , src .length ));
562+ absInplace (dst );
563+ }
564+
407565 private static int numberOfLeadingZeros (final int [] x , final int limit ) {
408566 int leadingIndex = limit - 1 ;
409567 while ((leadingIndex >= 0 ) && (x [leadingIndex ] == 0 )) leadingIndex --;
@@ -529,6 +687,7 @@ private static int[] knuthRemainder(final int[] dividend, final int[] modulus) {
529687 int n = modulus .length - limbShift ;
530688 if (n == 0 ) return new int [0 ];
531689 if (n == 1 ) {
690+ if (dividend .length == 1 ) return (new int [] {dividend [0 ] % modulus [0 ]});
532691 long d = modulus [0 ] & MASK_L ;
533692 long rem = 0 ;
534693 // Process from most significant limb downwards
0 commit comments