Inverting PhotoDNA
anishathalye.com
anishathalye.com
Microsoft claims:
> A PhotoDNA hash is not reversible, and therefore cannot be used to recreate an image.
This project shows that this isn't quite true: machine learning can do a pretty good job of reproducing a thumbnail-quality images from a PhotoDNA signature.
There has been some discussion in the past on HN about PhotoDNA: https://news.ycombinator.com/item?id=28378254. It has been claimed that PhotoDNA is reversible, but there was no public demonstration as far as I know.
In the photo of the child, facial features aren't reconstructable. Is it possible that PhotoDNA hashes might be sufficiently potato to not infringe on privacy or meaningfully (if not legally) count as explicit/illicit content?
Are secure lossy photo hashes possible? I feel like it'd require indistinguishability obfuscation (iO), where distinguishing a hash from zillions of random noise preimages would be guaranteed intractable. But I'm not sure if you could guarantee all the preimages matching the hash aren't all still recognizable.
Maybe you could set up some kind of adversarial system using your work as the adversary? (e.g. Set of transformed input images --[hashing neural net]-->hashes, then hashes--[Ribosome]-->preimage, then penalize hashing neural net (and reward Ribosome) based on distance of input image and preimage, along with rewarding the hashing net for distance from its hashes of other images + closeness of its hashes of similar transformed images.)
For the former, I guess when training the original model, a bunch of the Reddit images weren't available at crawl time. Wouldn't it make sense to somehow weed those out from the data set before the training?
I also didn't notice this issue until after I had trained the model and tried inverting hashes (didn't want to look through the NSFW dataset myself). And I thought it was amusing to leave it as-is (it demonstrates a point that issues from the dataset can be carried over to the results).
For the "image not available" ones, removing those in an automated way probably would be straightforward (could have used perceptual hashing for this task!).
For removing watermarks, there's some neat work from Dekel et al. in CVPR 2017: https://watermark-cvpr17.github.io/
This project generates discolored deformed thumbnails with maybe 12 pixels of resolution, and that's after addition of synthesized/imaginary data into them. Without priming by looking at the ground truth image, any attempts to guess what was in the images is just a Rorschach test.
Now as for completely theoretical possibility you can reverse any hash by brute-force. But that may not be computationally feasible. Now let's think what is easier: reversing a hash with few or many collisions? Let's take an edge case: a hash function hashes everything to just one value (not a very good hash function, but bear with me). That will be the easiest hash function to reverse, since any input is a right answer. Now as you reduce the number of collisions, the task becomes harder: you can divide images into disjoint sets such that each of them is defined by the hash value images in this set hash to, so if you have two images, each from distinct set, they hash to distinct values, and if they are in the same set, they hash to the same value. When you reduce the number of collisions the sets get smaller in size, but their amount grows. So for any given hash value which you want to reverse you need to check a bigger number of candidates to figure out which of the sets is the one for the given hash value (one candidate to check from each set). And that's assuming it would be feasible to just keep a list of those sets and their members, which it isn't, but illustrates the correlation. So actually it's easier to reverse when you have more collisions. It's counter-intuitive, because it's a different kind of reversing than what is usually meant by "reversing a function", which requires a function to be injective.
But: with fewer collisions you have higher likelihood that what you got as the result of reversing is what someone else used as input to the hash function (each of the sets is smaller, so with uniform distribution we get 1/n probability, where n is the number of elements in a given set of elements hashing to the same value).
Anyway, the sets I wrote about here are elements of a quotient set defined by the equivalence relation of hashing to the same value. You can read more on Wikipedia, if my description was a bit confusing: <https://en.wikipedia.org/wiki/Equivalence_class#quotient_set>
The third type of hashing is the dirt-simple hashing schemes you see used in hash tables; although even there denial-of-service resistance is still a desired property for public-facing web services.
You want SHA to be maximally non-continuous, but you certainly want the opposite for ssdeep for instance.
I know it should not be possible, but, still, I’d love to play with that kind of dataset.