user3416803
user3416803

Reputation: 379

Python itertools.combinations continue from certain value?

I used itertools to generate all combinations or printable ascii chars:

for combo in product('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;?@[\\]^_`{|}~ \t\n\r\x0b\x0c', repeat=10):

However, script was interrupted, but i got last sequence string. Is there a way to continue generation values using this string as starting sequence? Thank you.

UPD: I trying to solve some CTF task, by bruteforcing XOR cipher text. Xortool's output:

 2:   11.2%
   5:   15.6%
   7:   11.2%
  10:   18.4%
  15:   9.6%
  18:   6.6%
  20:   12.1%
  25:   5.8%
  30:   5.5%
  40:   4.0%

I can't see other solution now, at lest will try to bf 5-byte keys.

Upvotes: 1

Views: 602

Answers (3)

Alex Hall
Alex Hall

Reputation: 36033

Suppose the last string that was processed started with the character '5'. Then you can ignore all strings that started with previous characters, and set up the iteration like so:

for start in ('567...'):
    for subcombo in product('01234567...', repeat=9):
        yield (start,) + subcombo

However you really can't get through this search space. It's easy to calculate the total number of combinations:

>>> len('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;?@[\\]^_`{|}~ \t\n\r\x0b\x0c') ** 10
73742412689492826049L

While even if you could process a billion combinations a second, you wouldn't get close in a year:

>>> 1000000000 * 60 * 60 * 24 * 365
31536000000000000

Upvotes: 2

user2285236
user2285236

Reputation:

It may not be fast but with itertools.islice you can skip the first n of them:

c = itertools.islice(itertools.product('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;?@[\\]^_`{|}~ \t\n\r\x0b\x0c', repeat=10), 5, None)
c.next()
Out[39]: ('0', '0', '0', '0', '0', '0', '0', '0', '0', '5')

Upvotes: 1

John Zwinck
John Zwinck

Reputation: 249223

OK, look, this question doesn't really make sense because you have a loop which will probably run longer than your computer will, but I have an answer for you anyway!

Your loop produces tuples like this:

('0', '0', '0', '0', '0', '0', '1', 'C', '!', 'D')

Let's say that's the last one you saw on your previous run. So write your code like this:

resume_target = ('0', '0', '0', '0', '0', '0', '1', 'C', '!', 'D')
sequence = product(all_those_letters, repeat=10)
for combo in sequence:
    if combo == resume_target:
        break

for combo in sequence:
    # now do whatever you'd normally do

What I've done here is to simply "fast forward" with minimal computation through the first however-many combos were previously processed. This is simple and should be correct, but it does assume that you do a signficant amount of work with each combo--otherwise it's pointless to fast forward because you could just do a trivial amount of work over again.

Upvotes: 2

Related Questions