[undertow-dev] Nonce Format of SimpleNonceManager (UTF8)?

Bernd Eckenfels ecki at zusammenkunft.net
Thu Jun 5 15:30:50 EDT 2014


Hello,

I was a bit confused about the use of UTF-8 for converting a number to
bytes, but when I looked more closely, it is even more confusing why a
decimal number is used and converted here at all. If I understand it
right the format of the bytes and the length is unconstrained? I would
recommend to use 7 byte array with binary content. But even using Hex
or radix=36 strings would reduce the byte[] size without losing
entropy.

  private Nonce createNewNonce(NonceHolder previousNonce) {
      byte[] prefix = new byte[8];
      random.nextBytes(prefix);
      long timeStamp = System.currentTimeMillis();
      byte[] now = Long.toString(timeStamp).getBytes(UTF_8);
      String nonce = createNonce(prefix, now);
->

byte[] now =
Long.toString(timeStamp,36).getBytes(StandardCharsets.ISO_8859_1)

This makes the byte array shorter and the conversion slightly faster,
here are the timing for the various byte encoders on different string
formats (base-10,16,32,36) (8threads):

Benchmark                                      (number)   Mode   Samples        Score  Score error    Units
n.e.t.l.MyBenchmark.testGetBytesASCII     1401994160926  thrpt        80     4932,143       41,752   ops/ms
n.e.t.l.MyBenchmark.testGetBytesASCII       1466d5d2b1e  thrpt        80     5270,165       64,343   ops/ms
n.e.t.l.MyBenchmark.testGetBytesASCII         18pmlqaou  thrpt        80     5521,322      119,856   ops/ms
n.e.t.l.MyBenchmark.testGetBytesASCII          hw2f4hzy  thrpt        80     5929,315       62,562   ops/ms
n.e.t.l.MyBenchmark.testGetBytesBase      1401994160926  thrpt        80   154669,919     3845,919   ops/ms
n.e.t.l.MyBenchmark.testGetBytesBase        1466d5d2b1e  thrpt        80   155290,761     1678,557   ops/ms
n.e.t.l.MyBenchmark.testGetBytesBase          18pmlqaou  thrpt        80   152989,174     5648,101   ops/ms
n.e.t.l.MyBenchmark.testGetBytesBase           hw2f4hzy  thrpt        80   154360,497     3022,226   ops/ms
n.e.t.l.MyBenchmark.testGetBytesDefault   1401994160926  thrpt        80     2319,440       47,902   ops/ms
n.e.t.l.MyBenchmark.testGetBytesDefault     1466d5d2b1e  thrpt        80     2648,794       29,700   ops/ms
n.e.t.l.MyBenchmark.testGetBytesDefault       18pmlqaou  thrpt        80     3098,998       36,169   ops/ms
n.e.t.l.MyBenchmark.testGetBytesDefault        hw2f4hzy  thrpt        80     3364,678       33,274   ops/ms
n.e.t.l.MyBenchmark.testGetBytesLATIN1    1401994160926  thrpt        80     5202,078      189,594   ops/ms
n.e.t.l.MyBenchmark.testGetBytesLATIN1      1466d5d2b1e  thrpt        80     6166,294       64,541   ops/ms
n.e.t.l.MyBenchmark.testGetBytesLATIN1        18pmlqaou  thrpt        80     6677,003      130,301   ops/ms
n.e.t.l.MyBenchmark.testGetBytesLATIN1         hw2f4hzy  thrpt        80     6293,458      331,745   ops/ms
n.e.t.l.MyBenchmark.testGetBytesLower     1401994160926  thrpt        80    10332,605      114,527   ops/ms
n.e.t.l.MyBenchmark.testGetBytesLower       1466d5d2b1e  thrpt        80    10173,196      120,769   ops/ms
n.e.t.l.MyBenchmark.testGetBytesLower         18pmlqaou  thrpt        80    10392,109      150,898   ops/ms
n.e.t.l.MyBenchmark.testGetBytesLower          hw2f4hzy  thrpt        80    10584,135      140,522   ops/ms
n.e.t.l.MyBenchmark.testGetBytesUTF8      1401994160926  thrpt        80     4998,594      115,126   ops/ms
n.e.t.l.MyBenchmark.testGetBytesUTF8        1466d5d2b1e  thrpt        80     5184,154       72,303   ops/ms
n.e.t.l.MyBenchmark.testGetBytesUTF8          18pmlqaou  thrpt        80     5395,096       98,476   ops/ms
n.e.t.l.MyBenchmark.testGetBytesUTF8           hw2f4hzy  thrpt        80     5212,183      142,887   ops/ms

(Lower=loop over char array and use lower byte)

However I wonder if longToLower7Bytes(now) would be even more efficient?

Both changes needs to be reflected in verifyUnknownNonce() as well.
This would benefit from a byte nonce as well, as you could for example
not anymore trigger NumberFormatException with invalid nonces.

Want me to provide a binary version? How would the compatibility be
handled? (Using base10+ASCII is compatible, all other changes not). The native version minimizes the GC load as well:

Benchmark                                     (number)   Mode   Samples        Score  Score error    Units
n.e.t.l.MyBenchmark.testGetBytesNative   1401994160926  thrpt        80    31669,314      260,181   ops/ms
n.e.t.l.MyBenchmark.testGetBytesString   1401994160926  thrpt        80     2621,683       38,270   ops/ms

    @GenerateMicroBenchmark
    public byte[] testGetBytesNative() {
        byte[] res = new byte[8];
        long num = number;
        for(int i=7;i>=0;i--)
        {
            res[i] = (byte)(num & 255);
            num >>= 8;
        }
        return res;
    }

    @GenerateMicroBenchmark
    public byte[] testGetBytesString() {
        return Long.toString(number).getBytes(StandardCharsets.ISO_8859_1);
    }


Gruss
Bernd


More information about the undertow-dev mailing list