Computational Complexity Explained Through Cryptography and Randomness