## MS-DOS machine code (.COM file), 126 bytes ## (A 63-byte variant would be possible if the program was allowed to read its own code.) The first half (63 bytes) of the program are code and look like this: FC BE<3F>01 AC 50 88 C2 B4 02 CD 21 E8 1A 00 59 4E AC 81 FE<7E>01 7C 03 BE<3F>01 38 C1 75 F2 FE CA 75 EE 81 FE<3F>01 75 DB 8A 16 00 80 31 C0 8E D8 31 C9 AC 00 C2 E2 FB 0E 1F 88 16 00 80 C3 The second half (63 bytes) are data and are a 1:1 copy of the code. (In the 63-byte variant reading its own code, the bytes marked with "<>" have different values and the second half of the program is not present.) I'm also not sure about the random generator's probability distribution: The program uses the fact that the clock counters and other information modified by interrupts are stored in segment 0 to generate random numbers. Converted to assembly code the program looks like this: # 0x100: cld # Ensure SI is being incremented mov si, programEnd # Move SI to the first byte of the copy of the program nextOutput: lodsb # Load one byte of the program ... push ax # ... save it to the stack ... mov dl, al # ... and output it! mov ah, 2 int 0x21 call pseudoRandom # Create a random number (in DL) pop cx # Take the stored byte from the stack dec si # Go back to the last byte loaded nextSearch: lodsb # Load the next byte # If we loaded the last byte ... cmp si, 2*programEnd-0x100 jl notEndOfProgram # ... the next byte to be loaded ... mov si, programEnd # ... is the first byte of the program. notEndOfProgram: cmp cl, al # If the byte loaded is not equal to ... # ... the last byte written then ... jne nextSearch # ... continue at nextSearch! dec dl # Decrement the random number and ... jnz nextSearch # ... continue at nextSearch until the ... # ... originally random number becomes zero. cmp si, programEnd # If the last byte read was not the last byte ... jnz nextOutput # ... of the program then output the next ... # ... byte! # Otherwise fall through to the random number generator # whose "RET" instruction will cause the program to stop. # The random number generator: pseudoRandom: mov dl, [0x8000] # Load the last random number generated # (Note that this is uninitialized when # this function is called the first time) xor ax, ax # We use segment 0 which contains the ... mov ax, ds # ... clock information and other data ... # ... modified by interrupts! xor cx, cx # Prepare for 0x10000 loops so ... # ... all bytes in the segment are processed ... # ... once and the value of SI will be ... # ... unchanged in the end! randomNext: lodsb # Load one byte add dl, al # Add that byte to the next random number loop randomNext # Iterate over all bytes push cs # Restore the segment pop ds mov [0x8000], dl # Remember the random number ret # Exit sub-routine programEnd: ## Place a copy of the code as data here ##