java.lang.Object
java.lang.Thread
net.i2p.util.I2PThread
net.i2p.router.transport.crypto.X25519KeyFactory
All Implemented Interfaces:
Runnable, KeyFactory

public class X25519KeyFactoryextends I2PThread implements KeyFactory
Try to keep DH pairs at the ready. It's important to do this in a separate thread, because if we run out, the pairs are generated in the NTCP Pumper thread, and it can fall behind.

Pool sizes scale dynamically based on memory headroom, CPU pressure, and connection demand. The Tuner calls refreshPoolSize() every 15 seconds to adapt to changing conditions.

  • Field Details

    • lastInstance

      private static volatile X25519KeyFactory lastInstance
      The most recently created factory, reused on reconfigure.
    • _context

      private final I2PAppContext _context
      The app context.
    • _log

      private final Log _log
      Logger for the key factory.
    • _minSize

      private volatile int _minSize
      Smallest key queue allowed.
    • _maxSize

      private volatile int _maxSize
      Largest key queue allowed.
    • _calcDelay

      private volatile int _calcDelay
      Delay between the key calculations, in ms.
    • _targetMin

      private volatile int _targetMin
      Keys we want in the queue at least.
    • _targetMax

      private volatile int _targetMax
      Keys we stop calculating above.
    • _keys

      private final LinkedBlockingQueue<KeyPair> _keys
      The precalculated key pairs.
    • _isRunning

      private volatile boolean _isRunning
      True while the factory thread runs.
    • _checkDelay

      private long _checkDelay
      Interval of the settings recheck.
    • _emptyCount

      private final AtomicInteger _emptyCount
      Empties observed since last refresh — drives pool growth.
    • _usedCount

      private final AtomicInteger _usedCount
      Key consumption count since last refresh — drives fill ceiling.
    • PROP_DH_PRECALC_DELAY

      private static final String PROP_DH_PRECALC_DELAY
      Config key for the key calculation delay.
      See Also:
    • DEFAULT_DH_PRECALC_DELAY

      private static final int DEFAULT_DH_PRECALC_DELAY
      Default key calculation delay, in ms.
      See Also:
    • HARD_MIN

      private static final int HARD_MIN
      Absolute floor — never go below this even under memory pressure.
      See Also:
    • HARD_MAX

      private static final int HARD_MAX
      Absolute ceiling — never exceed this regardless of headroom.
      See Also:
    • KEY_SIZE_BYTES

      private static final int KEY_SIZE_BYTES
      Each keypair is ~64 bytes; this is the memory budget per key in bytes.
      See Also:
  • Constructor Details

    • X25519KeyFactory

      public X25519KeyFactory(I2PAppContext ctx)
      X25519KeyFactory.
      Parameters:
      ctx - the context supplying the log, stat manager and RNG for key generation
  • Method Details

    • computeTargetSizes

      void computeTargetSizes()
      Dynamically compute target pool sizes based on real-time system signals.

      Signals used:

      • Free memory headroom — more free memory = larger pool budget
      • Memory pressure — high usage = shrink aggressively
      • CPU load (job lag) — busy CPU = limit generation rate
      • Empty queue events — zero empties = low demand shrinks pool
      • Active peers — more connections = more key demand

      Memory budget: up to 2% of free heap when active, 0.5% when idle.

    • clampSmooth

      private static int clampSmooth(int prev, int target, int factor)
      Clamp a value to within a factor of the previous value. Prevents wild swings between refresh cycles.
      Parameters:
      prev - the previous cycle's value, center of the allowed range
      target - the desired new value to clamp
      factor - maximum multiplicative change allowed in either direction
      Returns:
      target clamped to prev/factor - prev*factor and to the hard limits
    • refreshPoolSize

      public void refreshPoolSize()
      Called by the Tuner every 15 seconds. Manages fill ceiling (_maxSize) based on demand and memory pressure. Does NOT override the Tuner-set _minSize — the Tuner owns that value via setMinSize(int).
    • recordEmpty

      public void recordEmpty()
      Record an empty-queue event for demand tracking. Called by getKeys() when the pool is depleted.
    • getInstance

      public static X25519KeyFactory getInstance()
      The most recently constructed factory.
      Returns:
      the most recently constructed factory, or null if none has been created yet
    • getMinSize

      public int getMinSize()
      Lower bound on the precalculated key queue size.
      Returns:
      the min size
    • setMinSize

      public void setMinSize(int min)
      The minimum precalc queue size.
      Parameters:
      min - the requested floor on queued keys, raised to HARD_MIN if lower
    • getMaxSize

      public int getMaxSize()
      Upper bound on the precalculated key queue size.
      Returns:
      the max size
    • setMaxSize

      public void setMaxSize(int max)
      The maximum precalc queue size.
      Parameters:
      max - the requested ceiling on queued keys, raised to the current minimum
    • getSize

      public int getSize()
      Returns the current number of precalc keys queued.
      Returns:
      how many prebuilt keypairs are waiting to be handed out, which counts keypairs rather than bytes and may be zero
    • shutdown

      public void shutdown()
      Note that this stops the singleton precalc thread. You don't want to do this if there are multiple routers in the JVM. Fix this if you care. See Router.shutdown(int).
    • run

      public void run()
      Precalculate keys until shutdown.
      Specified by:
      run in interface Runnable
      Overrides:
      run in class I2PThread
    • run2

      private void run2()
      Fills the key queue in the background.
    • getKeys

      public KeyPair getKeys()
      Pulls a prebuilt keypair from the queue, or if not available, construct a new one.
      Specified by:
      getKeys in interface KeyFactory
      Returns:
      an X25519 keypair for local ephemeral Diffie-Hellman use, either taken from the precalculation queue or newly generated
    • precalc

      private KeyPair precalc()
      Calculates one key pair.
      Returns:
      the new key pair
    • returnUnused

      public void returnUnused(KeyPair kp)
      Return an unused DH key builder to be put back onto the queue for reuse.
      Parameters:
      kp - the key pair taken from the pool but never consumed on the wire
    • addKeys

      private final boolean addKeys(KeyPair kp)
      Adds a precomputed key pair to the pool.
      Parameters:
      kp - the key pair to offer to the queue
      Returns:
      true if successful, false if at or above max size