CRACK Solution

Polynomial License

CRACK keygen (rolling hash + multiply mix + XOR whiten)

In-game screenshot of Polynomial License
In-game view
FamilyCRACK Graph0.896 DifficultyHard Ring05 IDz2_keygen_poly

Prerequisites

FINAL RIBBON

Unlocks

CHECK DIGIT

Accepted input 15053
Techniquekeygen (rolling hash + multiply mix + XOR whiten) Rulenonzero Sample15053

Walkthrough

Recover the accepted input below, then submit it to the CRACK verifier.

Reject Samples

  • 15052
  • 15054
  • 15153
  • 25053
  • 5053
  • 150530
  • 1505A
Verifier Listing
; z2_keygen_poly: username and serial keygen with a three-stage derivation. One
; correct serial per username, computed forward as:
;   1) FOLD : a rolling (djb2-style) hash over the username,  acc = acc*33 + c
;   2) MIX  : multiply the fold by an odd constant 0x4D
;   3) WHITEN: XOR with 0xAB
; Reverse the listing, replay the three stages over your username, format the
; serial. The USERNAME is BAKED in as constants. r0 = 1 on accept; rule: nonzero.
;
; 8-BIT NOTE: the source idea folded djb2 in 32-bit (seed 5381, *33), mixed by a
; 32-bit multiplier, and whitened with a 16-bit XOR. The core keeps the SAME three
; stages carried out mod 256 (the multiply by the odd 0x4D is reversible mod 256,
; as in the affine box), so every stage is faithful at the core's 8-bit width.
;
; SERIAL FORMAT (widened so the answer is not a single brute-forceable byte): a
; five-digit serial. The first three digits are the derived value; the last two
; are its mod-97 self-check, the same value-plus-check shape as z2_keygen_mod97.
; Baked username "dojo": acc seeds at 5 and folds to 177, *0x4D = 61, ^0xAB = 150,
; and 150 mod 97 = 53, so the one valid serial is "15053".

        len   r2
        cmp   r2, 5
        jnz   bad           ; serial is 5 ASCII digits: PPP CC

        ; every char must be a digit
        mov   r7, 0
dchk:   cmp   r7, 5
        jge   fold
        ldb   r0, [r7]
        cmp   r0, 0x30
        jl    bad
        cmp   r0, 0x39
        jg    bad
        inc   r7
        jmp   dchk

        ; --- stage 1: fold the baked username "dojo" (acc=acc*33+c) ------
        ; bytes: d=0x64 o=0x6F j=0x6A o=0x6F, seed 5
fold:   mov   r3, 5         ; r3 = acc
        mul   r3, 33
        add   r3, 0x64      ; 'd'
        mul   r3, 33
        add   r3, 0x6F      ; 'o'
        mul   r3, 33
        add   r3, 0x6A      ; 'j'
        mul   r3, 33
        add   r3, 0x6F      ; 'o' : r3 = fold (177)

        ; --- stage 2: mix (multiply by odd 0x4D, low byte) --------------
        mul   r3, 0x4D      ; r3 = mix (61)

        ; --- stage 3: whiten (XOR 0xAB) --------------------------------
        xor   r3, 0xAB      ; r3 = derived value (150)

        ; ================= validate the five-digit serial ==================
        ; PPP = the derived value, CC = value mod 97. For "dojo": 150 then 53.
        ; --- parse the 3-digit primary in r6, compare to the derived value:         mov   r6, 0
        mov   r7, 0
ppl:    cmp   r7, 3
        jge   ppd
        ldb   r0, [r7]
        sub   r0, 0x30
        mul   r6, 10
        add   r6, r0
        inc   r7
        jmp   ppl
ppd:    cmp   r6, r3
        jnz   bad

        ; --- check = value mod 97 (subtract loop) -------------------------
        mov   r5, r3
cmod:   cmp   r5, 97
        jl    havec
        sub   r5, 97
        jmp   cmod
havec:  ; r5 = value mod 97

        ; --- parse the 2-digit supplied check in r6, compare --------------
        mov   r6, 0
        mov   r7, 3
cpl:    cmp   r7, 5
        jge   cpd
        ldb   r0, [r7]
        sub   r0, 0x30
        mul   r6, 10
        add   r6, r0
        inc   r7
        jmp   cpl
cpd:    cmp   r6, r5
        jnz   bad

        mov   r0, 1
        ret
bad:    mov   r0, 0
        ret