简体   繁体   中英

How can I make all possible list combinations using reversible seeds?

I want to have a list made out of 100 items, each item being a value from 0-31 inclusive. I then want to be able to take one of these lists, and know what seed/input is necessary to randomly generate that exact list.

Using some suitable Linear Congruential Generator:

You could use this research paper by Pierre L'Ecuyer:

Tables_of_linear_congruential_generators_of_different_sizes_and_good_lattice_structure

The lowest power of 2 modulus for which the paper gives examples of (decently pseudo-random) LCGs is 2 30 , which is close to 1 billion. See table 4 of the paper. Just pick one of those LCGs, say:

u n+1 = ((116646453 * u n ) + 5437) mod 2 30

Each of your items is exactly 5 bits wide. If you decide to group your items 6 by 6, each group is exactly 30 bits wide, so can be considered as one state of this modulo 2 30 LCG.

From a initial group of 6 items, one step of the LCG will generate the next group, that is the next 6 items. And the paper tells you that the serie will look reasonably random overall.

Hence, you can regard the first 6 items as your “seed”, as you can reconstruct the whole list from its leftmost 6 items.

Even assuming that for the sake of obfuscation you started the visible part of the list after the seed, you would still have only about one billion possible seeds to worry about. Any decent computer would be able to find the left-hidden seed by brute force within a handful of seconds, by simulating the LCG for every possible seed and comparing with the actual list.

Sample Python code:

One can start by creating a class that, given a seed, supplies an unlimited serie of items between 0 and 31:

class LEcuyer30:
   def  __init__ (self, seed):
       self.seed      = seed & ((1 << 30) - 1)
       self.currGroup = self.seed
       self.itemCount = 6

   def __toNextGroup(self):
       nextGroup = ((116646453 * self.currGroup) + 5437) % (1 << 30)
       self.currGroup = nextGroup
       self.itemCount = 6

   def  getItem(self):
       if (self.itemCount <= 0):
           self.__toNextGroup()

       # extract 5 bits:
       word = self.currGroup >> (5 * (self.itemCount - 1))
       self.itemCount -= 1
       return (word & 31)

Test code:

We can create a sequence of 20 items and print it:

# Main program:

randomSeed = 514703103
rng = LEcuyer30(randomSeed)

itemList = []
for k in range(20):
    item = rng.getItem()
    itemList.append(item)

print("itemList = %s" % itemList)

Program output:

itemList = [15, 10, 27, 15, 23, 31, 1, 10, 5, 15, 16, 8, 4, 16, 24, 31, 7, 5, 8, 19]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM