Here is how the import works for you:
- you download a snapshot from a usb key found in a dark alley
- you start importing it, it displays the block hash it is importing
- you check in several places that this hash is indeed from the main chain
- if it checks up, you let it continue
Here is what the snapshot must contain (full variant):
- the current state of the ledger (balances, staking rights, etc.)
- the block header and operations of the whole chain
Here is how it is read and checked (not necessarily in order):
- the block headers are hashed locally, and since each block header contains the hash of its predecessor, the import procedure makes sure that all the headers included in the snapshot form a chain that starts at the imported block, and ends up at the expected genesis of mainnet
- the operations of each block are hashed, and the resulting lists of operation hashes are compared to the ones included in the imported block headers
- the context is imported, key by key, and the hashes of each key are recomputed locally
- the global hash of the context, which includes the hashes of all the keys, is computed, and the import procedure makes sure that it matches the hash written in the block header of the predecessor
- the current protocol is retrieved by reading a specific key in the context, so it is checked too as it is part of the context hash
- finally, to get some values that are the result of applying each block, such as the current lifetime of operations, and that are not included in the context, a single block application (using the protocol gathered above) is performed to get these values, and the resulting context hash is also checked
To validate new blocks after that, what the node needs is the context at that block, a few result values from the last block application, and a few block headers and operations from the past, all of which we've just shown to have been checked.
TL;DR: Hashes containing hashes that contain other hashes containing even more hashes, and that up to the genesis block, and up to each and every entry in the context, plus just a single run of block validation to make really sure. It is up to YOU to check the first hash of the series on more than one website or node, and then the import procedure does the rest.