All Implemented Interfaces:
Serializable, Comparable<BigInteger>

public class NativeBigIntegerextends BigInteger

BigInteger that takes advantage of the jbigi library for the modPow operation, which accounts for a massive segment of the processing cost of asymmetric crypto.

The jbigi library itself is basically just a JNI wrapper around the GMP library - a collection of insanely efficient routines for dealing with big numbers.

There are three environmental properties for configuring this component:

  • jbigi.enable: whether to use the native library (defaults to "true")
  • jbigi.impl: select which resource to use as the native implementation
  • jbigi.ref: the file specified in this parameter may contain a resource name to override jbigi.impl (defaults to "jbigi.cfg")

If jbigi.enable is set to false, this class won't even attempt to use the native library, but if it is set to true (or is not specified), it will first check the platform specific library path for the "jbigi" library, as defined by Runtime.loadLibrary(String)RESTRICTED - e.g. C:\windows\jbigi.dll or /lib/libjbigi.so, as well as the CLASSPATH for a resource named 'jbigi'. If that fails, it reviews the jbigi.impl environment property - if that is set, it checks all of the components in the CLASSPATH for the file specified and attempts to load it as the native library. If jbigi.impl is not set, it uses the jcpuid library described below. If there is still no matching resource, or if that resource is not a valid OS/architecture specific library, the NativeBigInteger will revert to using the pure java implementation.

When attempting to load the native implementation as a resource from the CLASSPATH, the NativeBigInteger will make use of the jcpuid component which runs some assembly code to determine the current CPU implementation, such as "pentium4" or "zen3". We then use that, combined with the OS, to build an optimized resource name - e.g. "net/i2p/util/libjbigi-freebsd-pentium4_64.so" or "net/i2p/util/jbigi-windows-zen3_64.dll". If that resource exists, we use it. If it doesn't (or the jcpuid component fails), we try a generic native implementation using "none" for the CPU e.g. "net/i2p/util/jbigi-windows-none_64.dll".

Running this class by itself does a basic unit test and benchmarks the NativeBigInteger.modPow vs. the BigInteger.modPow by running a 2Kbit op 100 times. At the end of each test, if the native implementation is loaded this will output something like:

native run time:        6090ms (60ms each)
java run time:          68067ms (673ms each)
native = 8.947066860593239% of pure java time

If the native implementation is not loaded, it will start by saying:

WARN: Native BigInteger library jbigi not loaded - using pure java

Then go on to run the test, finally outputting:

java run time:  64653ms (640ms each)
However, we couldn't load the native library, so this doesn't test much
See Also:
  • Field Details

    • _nativeOk

      private static boolean _nativeOk
      Did we load the native lib correctly?
    • _nativeOk3

      private static boolean _nativeOk3
      Is native lib loaded and at least version 3?
    • _nativeCTOk

      private static boolean _nativeCTOk
      Is native lib loaded and at least version 3, and GMP at least version 5?
    • _jbigiVersion

      private static int _jbigiVersion
      Version of the loaded jbigi library.
    • _libGMPVersion

      private static String _libGMPVersion
      Version of the GMP library in use.
    • _loadStatus

      private static String _loadStatus
      How the native library load went.
    • _cpuModel

      private static String _cpuModel
      CPU model the jbigi was chosen for.
    • _extractedResource

      private static String _extractedResource
      Resource the jbigi library was extracted from.
    • _doLog

      private static boolean _doLog
      Do we want to dump some basic success/failure info to stderr during initialization? this would otherwise use the Log component, but this makes it easier for other systems to reuse this class

      Well, we really want to use Log so if you are one of those "other systems" then comment out the I2PAppContext usage below.

      Set to false if not in router context, so scripts using TrustedUpdate.

    • JBIGI_OPTIMIZATION_ATHLON64

      private static final String JBIGI_OPTIMIZATION_ATHLON64
      The following libraries are be available in jbigi.jar in all I2P versions originally installed as release 0.6.1.10 or later (released 2006-01-16), for linux, freebsd, osx, and windows, EXCEPT: - athlon64 not available for freebsd - osx also does not have all of them.
      See Also:
    • JBIGI_OPTIMIZATION_PENTIUM4

      private static final String JBIGI_OPTIMIZATION_PENTIUM4
      jbigi build optimized for the Pentium 4.
      See Also:
    • JBIGI_OPTIMIZATION_ATOM

      private static final String JBIGI_OPTIMIZATION_ATOM
      The 7 optimizations below here are since 0.8.7.
      See Also:
    • JBIGI_OPTIMIZATION_CORE2

      private static final String JBIGI_OPTIMIZATION_CORE2
      jbigi build optimized for Core 2.
      See Also:
    • JBIGI_OPTIMIZATION_COREI

      private static final String JBIGI_OPTIMIZATION_COREI
      jbigi build optimized for Core i.
      See Also:
    • JBIGI_OPTIMIZATION_NANO

      private static final String JBIGI_OPTIMIZATION_NANO
      jbigi build optimized for Intel Atom Nano.
      See Also:
    • JBIGI_OPTIMIZATION_COREI_SBR

      private static final String JBIGI_OPTIMIZATION_COREI_SBR
      The optimization levels defined here are since 0.9.26.
      See Also:
    • JBIGI_OPTIMIZATION_COREI_HWL

      private static final String JBIGI_OPTIMIZATION_COREI_HWL
      jbigi build for Core i with Haswell instructions.
      See Also:
    • JBIGI_OPTIMIZATION_COREI_BWL

      private static final String JBIGI_OPTIMIZATION_COREI_BWL
      jbigi build for Core i with Broadwell instructions.
      See Also:
    • JBIGI_OPTIMIZATION_K10

      private static final String JBIGI_OPTIMIZATION_K10
      jbigi build optimized for AMD K10.
      See Also:
    • JBIGI_OPTIMIZATION_BULLDOZER

      private static final String JBIGI_OPTIMIZATION_BULLDOZER
      jbigi build optimized for AMD Bulldozer.
      See Also:
    • JBIGI_OPTIMIZATION_PILEDRIVER

      private static final String JBIGI_OPTIMIZATION_PILEDRIVER
      jbigi build optimized for AMD Piledriver.
      See Also:
    • JBIGI_OPTIMIZATION_STEAMROLLER

      private static final String JBIGI_OPTIMIZATION_STEAMROLLER
      jbigi build optimized for AMD Steamroller.
      See Also:
    • JBIGI_OPTIMIZATION_EXCAVATOR

      private static final String JBIGI_OPTIMIZATION_EXCAVATOR
      jbigi build optimized for AMD Excavator.
      See Also:
    • JBIGI_OPTIMIZATION_BOBCAT

      private static final String JBIGI_OPTIMIZATION_BOBCAT
      jbigi build optimized for AMD Bobcat.
      See Also:
    • JBIGI_OPTIMIZATION_JAGUAR

      private static final String JBIGI_OPTIMIZATION_JAGUAR
      jbigi build optimized for AMD Jaguar.
      See Also:
    • JBIGI_OPTIMIZATION_SKYLAKE

      private static final String JBIGI_OPTIMIZATION_SKYLAKE
      Jbigi optimization name for Skylake CPUs.
      See Also:
    • JBIGI_OPTIMIZATION_ZEN

      private static final String JBIGI_OPTIMIZATION_ZEN
      Jbigi optimization name for Zen CPUs.
      See Also:
    • JBIGI_OPTIMIZATION_ZEN2

      private static final String JBIGI_OPTIMIZATION_ZEN2
      Jbigi optimization name for Zen 2 CPUs.
      See Also:
    • JBIGI_OPTIMIZATION_ZEN3

      private static final String JBIGI_OPTIMIZATION_ZEN3
      Jbigi optimization name for Zen 3 CPUs.
      See Also:
    • JBIGI_OPTIMIZATION_ARM_ARMV8

      private static final String JBIGI_OPTIMIZATION_ARM_ARMV8
      ARM, 64-bit only.
      See Also:
    • JBIGI_OPTIMIZATION_X86

      private static final String JBIGI_OPTIMIZATION_X86
      None, no optimizations. The default fallback for x86.
      See Also:
    • JBIGI_COMPAT_LIST_NONE

      private static final String[] JBIGI_COMPAT_LIST_NONE
      CPU architecture compatibility lists, in order of preference.

      The list is organized by the chronological evolution of architectures. Totally unrelated architectures have separate lists. Sequences of architectures that aren't backwards compatible (performance wise) for some reasons have also been separated out.

      Really this could be represented by a DAG, but the benefits don't outweigh the implementation time.

    • JBIGI_COMPAT_LIST_ARM_ARMV8

      private static final String[] JBIGI_COMPAT_LIST_ARM_ARMV8
      Compatible builds for ARM ARMv8.
    • JBIGI_COMPAT_LIST_VIA

      private static final String[] JBIGI_COMPAT_LIST_VIA
      Compatible builds for VIA processors.
    • JBIGI_COMPAT_LIST_AMD_ATHLON

      private static final String[] JBIGI_COMPAT_LIST_AMD_ATHLON
      Compatible builds for AMD Athlon and Opteron.
    • JBIGI_COMPAT_LIST_AMD_APU

      private static final String[] JBIGI_COMPAT_LIST_AMD_APU
      Compatible builds for AMD APUs.
    • JBIGI_COMPAT_LIST_AMD_MAIN

      private static final String[] JBIGI_COMPAT_LIST_AMD_MAIN
      The main AMD product line.
    • JBIGI_COMPAT_LIST_INTEL_ATOM

      private static final String[] JBIGI_COMPAT_LIST_INTEL_ATOM
      Compatible builds for Intel Atom.
    • JBIGI_COMPAT_LIST_INTEL_PENTIUM

      private static final String[] JBIGI_COMPAT_LIST_INTEL_PENTIUM
      Compatible builds for Intel Pentium.
    • JBIGI_COMPAT_LIST_INTEL_CORE

      private static final String[] JBIGI_COMPAT_LIST_INTEL_CORE
      Compatible builds for Intel Core.
    • JBIGI_COMPAT_MAP

      private static final HashMap<String,String[]> JBIGI_COMPAT_MAP
      The mapping between CPU architecture and its compatibility list.
    • _isWin

      private static final boolean _isWin
      Operating systems. True when running on Windows.
    • _isOS2

      private static final boolean _isOS2
      Whether we are running on OS/2.
    • _isMac

      private static final boolean _isMac
      Whether we are running on macOS.
    • _isKFreebsd

      private static final boolean _isKFreebsd
      True on the KFreeBSD kernel.
    • _isFreebsd

      private static final boolean _isFreebsd
      True on the FreeBSD kernel.
    • _isNetbsd

      private static final boolean _isNetbsd
      True on the NetBSD kernel.
    • _isOpenbsd

      private static final boolean _isOpenbsd
      True on the OpenBSD kernel.
    • _isSunos

      private static final boolean _isSunos
      True on the SunOS kernel.
    • _isAndroid

      private static final boolean _isAndroid
      Whether we are running on Android.
    • _is64

      private static final boolean _is64
      Whether the JVM is 64-bit. See also: detecting the JRE bitness
    • _isX86

      private static final boolean _isX86
      Whether the CPU is x86.
    • _isArm

      private static final boolean _isArm
      Whether the CPU is ARM.
    • _libPrefix

      private static final String _libPrefix
      _isOS2 ? "" : "lib"); File name prefix for the native library.
    • _libSuffix

      private static final String _libSuffix
      _isOS2 ? ".dll" : _isMac ? ".jnilib" : ".so"); File name suffix for the native library.
    • sCPUType

      private static final String sCPUType
      The CPU type the jbigi was chosen for.
    • _cpuFamily

      private static String _cpuFamily
      Microarchitecture name for display, or null if unknown. Kept separate from sCPUType because that names the jbigi build to load, which stops at zen3 and so cannot name a Zen 4 or Zen 5 part.
    • cachedBa

      private volatile byte[] cachedBa
      Cached ba.
  • Constructor Details

    • NativeBigInteger

      public NativeBigInteger(byte[] val)
      BigInteger from the given big-endian representation.
      Parameters:
      val - big-endian two's-complement representation
    • NativeBigInteger

      public NativeBigInteger(int signum, byte[] magnitude)
      BigInteger from the given signum and magnitude.
      Parameters:
      signum - signum of the representation
      magnitude - big-endian binary representation
    • NativeBigInteger

      public NativeBigInteger(int bitlen, int certainty, Random rnd)
      Probable prime of given bit length.
      Parameters:
      bitlen - the bit length of the candidate prime to generate
      certainty - the Miller-Rabin rounds to run, so the probability of compositeness is at most 2^-certainty
      rnd - the source of the candidate bits and the Miller-Rabin witnesses
    • NativeBigInteger

      public NativeBigInteger(int numbits, Random rnd)
      Random non-negative BigInteger.
      Parameters:
      numbits - the minimum bit length of the value to generate
      rnd - the source of the random bits
    • NativeBigInteger

      public NativeBigInteger(String val)
      Decimal string representation.
      Parameters:
      val - the decimal digits, optionally signed, to parse
    • NativeBigInteger

      public NativeBigInteger(String val, int radix)
      String representation in the specified radix.
      Parameters:
      val - the digits to parse, optionally signed
      radix - the base the digits are written in, from 2 to 36
    • NativeBigInteger

      public NativeBigInteger(BigInteger val)
      Copy constructor from a BigInteger. Warning, not very efficient.
      Parameters:
      val - the value to copy, whose magnitude is read as a big-endian two's complement byte array
  • Method Details

    • resolveCPUType

      private static String resolveCPUType()
      Tries to resolve the best type of CPU that we have an optimized jbigi-dll/so for.
      Returns:
      A string containing the CPU-type or null if CPU type is unknown
    • nativeModPow

      private static byte[] nativeModPow(byte[] base, byte[] exponent, byte[] modulus)
      Calculate (base ^ exponent) % modulus.
      Parameters:
      base - big endian twos complement representation of the base (but it must be positive)
      exponent - big endian twos complement representation of the exponent
      modulus - big endian twos complement representation of the modulus
      Returns:
      big endian twos complement representation of (base ^ exponent) % modulus
      Throws:
      ArithmeticException - if modulus <= 0 (since libjbigi version 3)
    • nativeModPowCT

      private static byte[] nativeModPowCT(byte[] base, byte[] exponent, byte[] modulus)
      Calculate (base ^ exponent) % modulus. Constant Time.
      Parameters:
      base - big endian twos complement representation of the base (but it must be positive)
      exponent - big endian twos complement representation of the exponent
      modulus - big endian twos complement representation of the modulus
      Returns:
      big endian twos complement representation of (base ^ exponent) % modulus
      Throws:
      ArithmeticException - if modulus <= 0
    • nativeModInverse

      private static byte[] nativeModInverse(byte[] base, byte[] d)
      Compute the modular inverse of base modulo d.
      Parameters:
      base - big endian twos complement representation of the number to invert
      d - big endian twos complement representation of the modulus
      Returns:
      big endian twos complement representation of the inverse
      Throws:
      ArithmeticException - if the modulus is not positive or the inverse does not exist
    • nativeJbigiVersion

      private static int nativeJbigiVersion()
      The jbigi version, only available since jbigi version 3.
      Returns:
      the version number reported by the loaded native library
    • nativeGMPMajorVersion

      private static int nativeGMPMajorVersion()
      The libmp major version, only available since jbigi version 3.
      Returns:
      the major version number of the libmp the native library links against
    • nativeGMPMinorVersion

      private static int nativeGMPMinorVersion()
      The libmp minor version, only available since jbigi version 3.
      Returns:
      the minor version number of the libmp the native library links against
    • nativeGMPPatchVersion

      private static int nativeGMPPatchVersion()
      The libmp patch version, only available since jbigi version 3.
      Returns:
      the patch version number of the libmp the native library links against
    • fetchJbigiVersion

      private static int fetchJbigiVersion()
      The jbigi version, fetched from the native library.
      Returns:
      0 if no jbigi available, 2 if version not supported
    • setVersions

      private static void setVersions()
      Store the jbigi and libgmp versions. Call after loading. Sets _jbigiVersion, _nativeOk3, and _libGMPVersion.
    • getJbigiVersion

      public static int getJbigiVersion()
      The jbigi version, fetched from the native library.
      Returns:
      0 if no jbigi available, 2 if version info not supported
    • getLibGMPVersion

      public static String getLibGMPVersion()
      The libgmp version string.
      Returns:
      "unknown" if no jbigi available or if version not supported
    • modPow

      public BigInteger modPow(BigInteger exponent, BigInteger m)
      Compute base^exponent mod m using the native library.
      Overrides:
      modPow in class BigInteger
      Parameters:
      exponent - must be positive
      m - must be positive
      Throws:
      ArithmeticException - if m <= 0 or exponent <=0
    • modPowCT

      public BigInteger modPowCT(BigInteger exponent, BigInteger m)
      Compute base^exponent mod m in constant time using the native library.
      Parameters:
      exponent - must be positive
      m - must be positive and odd
      Returns:
      this value raised to the exponent modulo m, falling back to the variable-time computation when constant-time native code is unavailable
      Throws:
      ArithmeticException - if m <= 0 or m is even or exponent <=0
    • modInverse

      public BigInteger modInverse(BigInteger m)
      Compute the modular inverse of this value modulo m using the native library.
      Overrides:
      modInverse in class BigInteger
      Throws:
      ArithmeticException - if not coprime with m, or m <= 0
    • toByteArray

      public byte[] toByteArray()
      Cached byte array representation, filled in on first call.
      Overrides:
      toByteArray in class BigInteger
    • isNative

      public static boolean isNative()
      Whether native methods will be used by this class.
      Returns:
      True iff native methods will be used by this class
    • loadStatus

      public static String loadStatus()
      Human-readable status of the native library load.
      Returns:
      A string suitable for display to the user
    • getLoadedResourceName

      public static String getLoadedResourceName()
      The name of the library loaded, if known. Null if unknown or not loaded. Currently non-null only if extracted from jbigi.jar.
      Returns:
      the loaded resource name
    • cpuType

      public static String cpuType()
      Detected CPU type for jbigi optimization.
      Returns:
      the detected architecture, or "unrecognized" if it could not be probed
    • cpuFamily

      public static String cpuFamily()
      Processor family for the console info page, named the way a reader would expect rather than the way the jbigi library is named. The optimization name is imprecise at the top of the AMD range on purpose - zen3 is the newest tuned build, so a Zen 4 or Zen 5 part resolves to it - and "none" only says that no tuned build matched, which is not a processor to print.
      Returns:
      the family name, or null if the processor could not be classified
    • amdFamily

      public static String amdFamily(AMDCPUInfo cpu)
      Microarchitecture name for an AMD CPU, reported at the newest generation its compatibility flags support. The jbigi build stops at zen3, so the library name cannot tell a Zen 3 part from a Zen 4 or Zen 5 one - naming the library here would hide which chip the machine actually has.
      Parameters:
      cpu - the probed CPU, may be null
      Returns:
      the generation name, or null if it is not a Zen CPU
    • familyFor

      static String familyFor(String type)
      Display name for a jbigi optimization name, or null when the name carries no information about the processor - "none" only says that no tuned build matched. AMD is named from the CPU flags instead, by amdFamily(AMDCPUInfo). Package visible for testing.
      Parameters:
      type - the optimization name, or null
      Returns:
      the family name, or null if there is nothing useful to show
    • cpuModel

      public static String cpuModel()
      CPU model string from CPUID.
      Returns:
      the model name reported by the CPU, or null if it could not be read
    • loadNative

      private static final void loadNative()

      Do whatever we can to load up the native library backing this BigInteger's native methods. If it can find a custom built jbigi.dll / libjbigi.so, it'll use that. Otherwise it'll try to look in the classpath for the correct library (see loadFromResource). If the user specifies -Djbigi.enable=false it'll skip all of this.

      Load order (using linux naming with cpu type "xxx")
      - filesystem libjbigi.so
      - jbigi.jar libjbigi-linux-xxx_64.so
      - jbigi.jar libjbigi-linux-yyy_64.so 0 or more other alternates
      - jbigi.jar libjbigi-linux-none_64.so
      
      Only 64-bit native libraries are shipped.
    • debug

      private static void debug(String s)
      Log a native math debug message.
      Parameters:
      s - the message to log
    • info

      private static void info(String s)
      Logs an informational message about the library load.
      Parameters:
      s - the message to log
    • warn

      private static void warn(String s)
      Logs a warning about the library load.
      Parameters:
      s - the message to log
    • warn

      private static void warn(String s, Throwable t)
      Log a native math warning.
      Parameters:
      s - the message to log
      t - the cause to print and record, or null
    • error

      private static void error(String s)
      Log a native math error.
      Parameters:
      s - the message to log
    • error

      private static void error(String s, Throwable t)
      Log a native math error with its cause.
      Parameters:
      s - the message to log
      t - the cause to print and record, or null
    • loadGeneric

      private static final boolean loadGeneric(String name)

      Try loading it from an explicitly build jbigi.dll / libjbigi.so first, before looking into a jbigi.jar for any other libraries.

      Parameters:
      name - the library name to load, null means do nothing
      Returns:
      true if it was loaded successfully, else false
    • loadFromResource

      private static final boolean loadFromResource(String resourceName)

      Check all of the jars in the classpath for the file specified by the environmental property "jbigi.impl" and load it as the native library implementation. For instance, a windows user on a p4 would define -Djbigi.impl=win-686 if there is a jbigi.jar in the classpath containing the files "win-686", "win-athlon", "freebsd-p4", "linux-p3", where each of those files contain the correct binary file for a native library (e.g. windows DLL, or a *nix .so).

      This is a pretty ugly hack, using the general technique illustrated by the onion FEC libraries. It works by pulling the resource, writing out the byte stream to a temporary file, loading the native library from that file. We then attempt to copy the file from the temporary dir to the base install dir, so we don't have to do this next time - but we don't complain if it fails, so we transparently support read-only base dirs.

      Parameters:
      resourceName - the resource to load, named by the "jbigi.impl" property, null means do nothing
      Returns:
      true if it was loaded successfully, else false
    • getResourceList

      private static List<String> getResourceList()
      Generate a list of resources to search for, in-order. See loadNative() comments for more info.
      Returns:
      non-null
    • getMiddleName2

      private static final String getMiddleName2(boolean optimized)
      The middle part of the native library name, based on the CPU type.
      Parameters:
      optimized - true to use the detected CPU type, false for the generic "none" library
      Returns:
      may be null if optimized is true
    • getMiddleName1

      private static final String getMiddleName1()
      The middle part of the native library name, for a non-optimized library.
      Returns:
      may be null if optimized is true; returns jbigi-xxx-none if optimize is false