Interesting question. After all, it's the main job of a computer to come up with deterministic results, which is pretty much the opposite of pure randomness.

In reality, coming up with a series of non-deterministic numbers from a digital circuit only is considered technically impossible. Modern computers use "known noise" in their peripheral devices or even dedicated noise generator circuits to seed their random number generator. Older home computers didn't really have that much periphery to choose from so used "close-to random" values as a seed like video flyback counters or "time since switched on".

Once you have a (more or less random) seed (initial value), a simple RNG (Random Number Generator) typically consists of an LFSR (linear feedback shift register) that runs the seed through a binary polynom, generating a new value from the previous one that "looks" random (picture source: Wikipedia) (Today's computers tend to use much more sophisticated RNGs)

Note what "looks like hardware" in the picture can easily be reproduced by software in a computer. A random number would then just be the current value of that 8 bit register. A new random value is being generated on every fetch by shifting the old value one bit and feeding back the "carry" and bit positions determined by the chosen polynom into the lowest bit.

In pseudocode, an RNG looks somewhat like this (implements the above picture):

carry = (x & $80) != 0 oldx = x x = x >> 1 x |= (carry + (oldx & $04) > 0 + (oldx & $10) > 0 + (oldx & $20) > 0) != 0

In reality, most of the RNGs did, different from the example, normally use 16-bit shift registers and the polynoms might look different.

The initial state i.e. the seed of the shift register is normally set by the RANDOMIZE (or similar) Basic keyword. This might be the most misunderstood and misused basic keyword ever - It somehow seems to imply to make the RNG "more random" but instead does the exact opposite - By seeding the RNG with a constant number, you can make different computers with the same BASIC produce the exact same sequence of random numbers. Using this technique you can easily create encryption programs that can only be decrypted by the same RNG using the initial seed as a key (i.e. cyphers produced by the Commodore C64 that can only be deciphered by a C64). I also remember a Basic program I once wrote for the Sinclair QL that calculated the value of PI by simulating rainfall (random coordinates) onto a circle in a square and determining whether the raindrop fell into the circle.

A "cryptographically secure" source of a seed for the RNG is not known to me from early computers - At least not of home computers. After all, proper encryption which is the main use for RNGs was not necessary on a non-networked computer (most of the early computers were) as long as you had a proper door in front of it. Only the development of larger networks and the internet made encryption really necessary - before that time, you could simply rely on physically securing computers.