IO and ST RealWorld are indeed represented the same--in today's GHC. It would be possible to implement the same ST interface differently (e.g., as an operational monad). Adding ioToST to the public interface commits not only GHC, but also future Haskell implementations, to a similar representation.
Note: I recently noticed a real difference between IO and ST with regard to strictness analysis. In IO,
m >>= undefined
is *not* bottom: it may perform an observable action. In ST, it is bottom; anything it mutates is guaranteed to vanish in a puff of smoke.
So assuming that these have the same representation actually introduces some complications for optimization.