This has almost certainly been raised before by others, but there seems to be something uncomfortable using .size() (of a List or Set for example) as the seed parameter as in Random.nextInt(l.size()).
This approach will bind the search space for a random int to the length of the array/ list/set, which is not going to be the same volume of search space on a set such as for example : 4,36,90,203,480017.Here, nextInt(size()) means there is an equal chance of any one of the five index positions being returned, whereas the true search space ought to be 480017 , i.e. the nextInt on the *largest* value in the list. IOW, the two approaches are conceptually / philosophically different - size() by itself never needing a re-iteration to obtain the int, whereas nextInt on the largest value in a non-contiguous set or any set not having values matching its indexing will require (many) more calls and therefore be nominally more random, than nextInt(size()).
There are plenty of guru sites where .size() is used of course : i.a. here
Perhaps in encryption terms, the potentially far smaller search space of nextInt(size()) will have an impact on the crackability algo, and hence time ?
Any thoughts ?