Skip to content
petrs edited this page Jul 25, 2017 · 24 revisions

Welcome to the JCMathLib wiki!

Main components of JCMathLib

The JCMathLib is focused on the provision of low-level operations with large numbers (Bignat, Integer) and ECPoints which executes reasonably fast and requires only a decent amount of resources (especially transient RAM which is a scarse resource). The implementation is fully based on the public API and requires no proprietary functions.

The JCMathLib contains the following principal components:

Functional

  • Bignat.java - provides optimized implementation of big natural numbers (without sign). Multiple Bignats are usually allocated.
  • Integer.java - provides an implementation of signed big integers. Use heavily underlying Bignat. Multiple Integer objects are usually allocated.
  • ECPoint.java - provides low-level operations for a point on specified elliptic curve. Multiple ECPoints are usually allocated.
  • ECCurve.java - holds the definition of used curve for particular ECPoint. A single ECCurve object is usually allocated and shared between multiple ECPoints unless multiple different curve specifications are used. ECCurve can be initialized from static arrays (for well-known curves) without any additional memory allocation or copy.

Supportive

  • ObjectAllocator.java - management class which controls the allocation of new arrays based on a specification of the array memory placement (transient RAM vs. persistent EEPROM) with an easy change.
  • ObjectLocker.java - management class for logical locking and unlocking of arrays and other objects. Used to detect the conflicting use of shared resource (e.g., memory array) in nested methods and also to automatically clear the sensitive intermediate values left from previous computation before or after use (or both).
  • Bignat_Helper.java - provides all helper pre-allocated arrays and objects necessary to implement the functionality of Bignat methods. As there is no concurrency in Java Card, all Bignat objects share single Bignat_Helper object.
  • ECPoint_Helper.java - provides all helper pre-allocated arrays and objects necessary to implement the functionality of ECPoint methods. All ECPoint objects share single ECPoint_Helper object. ECPoint heavily utilizes Bignat objects.
  • OCConfig.java - aggregation class for all helper objects listed above together with definitions of lengths as required for particular EC curve. The single OCConfig object is created.
  • PM.java - Utility class for performance profiling. Contains a definition of performance trap constants and trap reaction for relevant of operation from Bignat and ECPoint.
  • ReturnCodes.java - List of custom return codes returned by the library.
  • SecP256r1.java, P512r1.java - constants defining well-known elliptic curves.

Examples & tests

  • ECExample.java - very simple example applet of allocation and use of ECPoint. No communication with a client-side application.
  • OCUnitTests.java - applet used to execute unit tests for Bignat/Integer and ECPoint of JCMathLib. UnitTestsClient client-side application executes and processes relevant APDU commands and responses.

Management of pre-allocated shared objects

As already noted, memory (especially RAM) is a precious resource on the smart cards. But the implementation of more complex operations like square root (Bignat.sqrt_FP()) or addition of two points (ECPoint.add()) requires multiple arrays/objects to store intermediate results. Reuse of a shared array is common Java Card development practice but is also contributing to less readable code (tempRAMBuffer everywhere) and introduce the potential for corruption or information-leakage bugs. We, therefore, aim to provide a pool of shared arrays and objects (which is a must due to limited memory) yet achieve readable code and safe reuse.

More specifically:

  • The variables to store intermediate results within a method have human-understandable names. E.g., if we need to store nominator computed during ECPoint.add() method, the variable name is fnc_add_nominator (attribute of ECPoint_Helper instead of method's local variable).
  • As little memory arrays (or Bignat objects) as possible are allocated to a pool of shared objects. E.g., ECPoint implementation requires only six different Bignats which are stored in ECPoint_Helper as attributes named helperEC_BN_A to helperEC_BN_F.
  • The attributes representing local variables (e.g., fnc_add_nominator) are assigned with reference to one of shared object (e.g., fnc_add_nominator = helperEC_BN_B) according to the carefully planned mapping. The mapping is done only once during an allocation of helper objects. As a result, many local variables with sensible names are used yet represented by an only small number of actually allocated objects.
  • The mapping must be carefully done so that two local variables with the same underlying shared object are never used at the same time. As there is no concurrency in Java Card, we don't need to be worry of overlap by two executions of the same method. But the conflict within the same method can still arise and especially in the nested calls. To prevent corruption, every variable is logically locked before its use (fnc_add_nominator.lock()) and unlocked when not used anymore (fnc_add_nominator.unlock()). If the object is already locked, an exception is emitted. This way, it's very easy to detect the conflict. If detected, different mapping needs to be used or a number of underlying shared objects must be increased.
  • The locking is implemented as dedicated method lock() and unlock() of Bignat objects and via ObjectLocker class for plain arrays and other objects.
  • The locking and unlocking also provide easy way how to prevent unintended information leak. The memory of shared object can be automatically erased on a lock on unlock (depending on configuration flags) inside lock() and unlock() function.

Important: Java Card programming is not exactly equal to standard Java

Note that Java Card programming is different from standard Java programming although basic Java Card applet can be compiled using javac tool. The list of notable differences can be found in Java Card documentation, but the most important ones are:

  • Memory is very limited (especially fast transient RAM), an allocation is slow and garbage collection can be completely missing. As a result, all require arrays and objects are usually allocated in the applet constructor and reused during the whole lifetime of an applet on a card.
  • Operator new will put an object into persistent memory which will persist loss removal of a card from a smart card reader but is also quite slow to write. If an array is to be allocated in fast RAM, a dedicated method like JCSystem.getTransientByteArray() needs to be is used.
  • Object oriented hierarchies and features are used, but only in a limited fashion. Frequently accessed attributes might be public instead of modified via setters. A large number of arguments slow down method calls.
  • For performance reasons, copy-free programming is preferred. Instead of creating new and new arrays with intermediate results, the in-place modification is performed with array passed together with start offset and data length. Dedicated methods from JCSystem class are used for fast memory operations like copy or fill or arrays.
  • As a card environment defends itself against an adversary, it also makes difficult to debug and profile applet on a card. As a result, a code is usually first debugged in a simulator. But as a simulator itself is never a perfect representation of real card, execution on real hardware usually requires additional debugging.

So don't be surprised to see some deviations from good Java programming practices. But if you will spot something incorrect, let us know please - possibly by pull request? :)

  • Prerequisities of used smart cards: JavaCard API, EC / RSA / memory
  • Compilation, upload, dependencies
    • ant-javacard
    • GlobalPlatformPro
  • Performance on real cards (table)
  • Example use for ECPoint operations
  • Example use for Bignat and Integer operations
  • Memory management of shared objects and logical locking
    • Easy to set RAM or EEPROM placement for array
    • Allows for nuanced tradeoff between resource consumption (RAM is very limited, usually less than 3kB) and speed performance (data in RAM are written faster)
  • Performance profiler
    • Prerequisities and caveats
    • Setup and execution
    • How to intepret results
Clone this wiki locally