Here’s what happens. Your instance of Chrome hashes your username and password and encrypts that value with an ephemeral key which doesn’t leave Chrome, Kc
Google gets the encrypted cred-hash and applies a second round of encryption with a key only known to Google, Kg. They return the doubly-encrypted cred-hash, and also return 256 candidates encrypted with just Kg for you to compare against, those 256 candidates are selected based on a clear-text 3 byte prefix that Chrome also sends them.
When Chrome gets the results back, it decrypts the cred-hash using Kc which results in the cred-hash now being encrypted only with Kg; coincidentally this is the same exact key used to encrypt the candidates, allowing Chrome to do a simple byte-compare to see if there’s a match between your cred-hash and the encrypted breach candidates.
The cool part is the encryption operation is basically communicative. You can add your layer of encryption first, send the value to Google, they add their encryption and you get the double-encrypted blob back, and then you remove your encryption to end up with a plaintext encrypted just with Google’s key, even though Google never saw the plaintext, and you never saw their key.
This trick allows your browser, and only your browser, to compare your cred-hash against the breached cred-hashes while all the data you are comparing is actually encrypted with a secret key held by Google that never leaves Google’s server.
The only information leak is the 3-byte hash prefix to identify the slice of the comparison set. This is definitely not nothing, but perhaps it is a reasonable trade-off.