My understanding of Quorum is that private contracts have encrypted states hence I am confused as to how they reach consensus and prevent double spending. If each state is encrypted how can the nodes be sure a tx isn't double spent as the data is encrypted?
Quorum has two type of transactions, public transactions and private transaction. Public transactions get processed similar to as how public Ethereum processes transactions, get included in blocks and derive a public state.
Private transactions are flagged as "private" but are otherwise publicly visible and also get included in the blocks; the payload (data) is encrypted and can be decrypted by anyone who is part of the "private group". The private state isn't publicised because it's useless to anyone else but yourself and serves as the root-node in the private trie.
Private transactions can interact with public contracts on a read-only base. This is a restriction otherwise public state could be modified by private state, which would in turn yield different state across clients. Public transactions can not interact with private state.
Quorum has a privateFor: that contains a contract, state and related transactions to the parties involved. But, the parties involved in the private transaction see the contract. They execute the functions and hold the state in manner that is very similar to ethereum. It's just that non-participants who are not on the privateFor: list can't interpret the transactions.
Hope it helps.