;
; pker's Random Number Generator (PKRNG)
; ======================================
;
;
; Description
; -----------
;
; PKRNG is a random number generator. It can be used for MASM, TASM, FASM, etc. It
; containz   four   procedurez:  __randomize,   __random   and   __m_seq_gen   and
; __random_rdtsc. __randomize procedure is for generating initial seed in the seed
; field,   which  specified  as  parameter.   The __m_seq_gen procedure is used to
; generate   m-sequence,  which  used  by __random,  which generate random numberz
; finally. __random_rdtsc is the simplest one, it just get the RDTSC and divide it
; by the range given as parameter.
;
;
; How to use PKRNG
; ----------------
;
; When using MASM or TASM to initialize seed field:
;
;       mov   edi,offset dwSeed
;       call  __randomize
;
; The get a random number in eax:
;
;       mov   eax,offset dwSeed
;       mov   ecx,32                    ; get a random number between 0~31
;       call  __random
;
;
; Same thing happened with FASM:
;
;       mov   edi,dwSeed
;       call  __randomize
;
;       mov   eax,dwSeed
;       mov   ecx,32                    ; get a random number between 0~31
;       call  __random
;
;
; Copyright
; ---------
;
; (c) 2004. No rightz reserved. Use without permission :P.
;


;
; __randomize procedure
; =====================
;
;
; Description
; -----------
;
; This function use RDTSC instruction to generator a random number in order to
; initialize the seed field.
;
;
; Parameterz and Return Values
; ----------------------------
;
; input:
;       edi --- points to the seed field
; output:
;       nothing
;

__randomize:    pushad
                db      0fh,31h                 ; RDTSC
                add     eax,edx                 ; ...
                stosd                           ; fill in the seed buffer
                popad
                ret


;
; __random procedure
; ==================
;
;
; Description
; -----------
;
; This function generates a random number and rewrite the seed field. The function
; first get a 32 bit m-sequence, which then multiply with the previous seed,  with
; __m_seq_gen procedure.  And then, it calls __m_seq_gen again to generate another
; m-sequence  to make noise by adding on the DWORD calculated before.  Also,  this
; result is the new seed, and will be write to the seed field which pointed by EAX
; as argument.  Finally, the seed is divided by ECX, and return the modulus, which
; is the expected random number.
;
;
; Parameterz and Return Values
; ----------------------------
;
; input:
;       eax --- pointz to the random seed field
;       edx --- the range of the random number to be generated
; output:
;       eax --- random number as result
;

__random:       pushad
                xchg    ecx,edx
                mov     edi,eax
                mov     esi,eax
                lodsd                           ; get the previous seed value
                mov     ebx,eax
                mov     ebp,ebx
                call    __m_seq_gen             ; generate a m-sequence
                imul    ebp                     ; multiply with the previous seed
                xchg    ebx,eax
                call    __m_seq_gen             ; generate anothe m-sequence
                add     eax,ebx                 ; to make noise...
                add     eax,92151fech           ; and some noisez...
                stosd                           ; write new seed value
                xor     edx,edx
                div     ecx                     ; calculate the random number
                mov     [esp+28],edx            ; according to a specified range
                popad
                ret


;
; __m_seq_gen procedure
; =====================
;
;
; Description
; -----------
;
; This function use a  PN  (Pseudo Noise)  generator to generate m-sequencez.  The
; configuration of the generator shows below (figure 1):
;
;                    (module 2 addition)
;                           ___
;                          /   \
;              +---------- | + | <------------------------------+
;              |           \___/                                |
;              |             A                                  |
;              |    +-----+  |   +-----+               +-----+  |
;              +--> | D31 | -+-> | D30 | ---> ... ---> | D01 | -+-> output
;                   +-----+      +-----+               +-----+
;                      A            A                     A
;                      |            |                     |
;   CLK ---------------+------------+---------------------+
;
;                     figure 1. m-Sequence Generator
;
;
; Parameterz and Return Values
; ----------------------------
;
; input:
;       eax --- a non-zero random number, which could  be generated by RDTSC or
;               GetTickCount or such functionz
; output:
;       eax --- the result of the function
;

__m_seq_gen:    pushad
                xor     esi,esi                 ; use to save the 32bit m-sequence
                push    32                      ; loop 32 times (but it's not a
                pop     ecx                     ; cycle in the m-sequence generator)
msg_next_bit:   mov     ebx,eax
                mov     ebp,ebx
                xor     edx,edx
                inc     edx
                and     ebp,edx                 ; get the lowest bit
                dec     cl
                shl     ebp,cl
                or      esi,ebp                 ; output...
                inc     cl
                and     ebx,80000001h           ; \
                ror     bx,1                    ;  \
                mov     edx,ebx                 ;   \
                ror     ebx,16                  ;    module 2 addition
                xor     bx,dx                   ;   /
                rcl     ebx,17                  ;  /
                rcr     eax,1                   ; /
                loop    msg_next_bit
                mov     [esp+28],esi
                popad
                ret


;
; __random_rdtsc procedure
; ========================
;
;
; Description
; -----------
;
; This is the simplest RNG in the packet. Well, nothing to explain :P
;
;
; Parameterz and Return Value
; ---------------------------
;
; input:
;       ecx --- the range of the random number to be generated
;
; output:
;       eax --- random number as result
;

__random_rdtsc: pushad
                db      0fh,31h
                add     eax,edx
                xor     edx,edx
                or      ecx,ecx
                jz      rnd_rdt_no_range
                div     ecx
                xchg    eax,edx
rnd_rdt_no_range:
                mov     [esp+28],eax
                popad
                ret