I'm not sure, but there may be some hash functions for which H(concat(a, a)) = F(H(a)). I'd worry a little about their security in some contexts - particularly if that generalized beyond just duplication, it seems likely vulnerable to length extension attacks if used for HMAC, &c - but for password hashing it might be fine and would clearly be better than plain text. It's not impossible they were already using a hash for which that's true - just unlikely.
Another possibility would be that they compute and send both H(a) and H(firsthalf(a)), if fisthalf(a) == secondhalf(a). That would work with any hash function, but I think would not appreciably increase security.
there may be some hash functions for which H(concat(a, a)) = F(H(a))
If H is secure then F is not computable. If they can do a trick like this then their hashing is no good.
Another possibility would be
Yeah, you can approach it like a puzzle and figure out what crazy set up they could have, but Occam's Razor has to apply at some point. I'm betting they did the dumb thing, not the strange thing that is mostly pointless.
"If H is secure then F is not computable. If they can do a trick like this then their hashing is no good."
Can you point to something more than assertion, here?
"Yeah, you can approach it like a puzzle and figure out what crazy set up they could have, but Occam's Razor has to apply at some point. I'm betting they did the dumb thing, not the strange thing that is mostly pointless."
It's mostly pointless, but it's increasingly common knowledge that the dumb thing is dumb. It's more subtle that the pointless thing is pointless. If I had to bet, I'd also bet that they did the dumb thing, I just think it's marginally less conclusive than had been implied.
> there may be some hash functions for which H(concat(a, a)) = F(H(a))
I'll give a shot at why this implies that H is not a secure hash function, though I could be wrong. The outputs of a secure hash function should be randomly distributed across the set of all possible outputs. If H is a secure hash function that outputs a value in the set {0,1}^128 (a 128 bit output), then H(a) and H(a+a) should both be 128 bit outputs whose mapping are indistinguishable from values chosen truly at random from this set. Although there is a discernable pattern in the two inputs to H (the concatenation), there should be no discernable pattern in the two outputs of H that you could use to reliably map H(a) to H(a+a) for any given a.
I don't think this follows. "Random output" is an idealized model that no actual, specific hash function achieves. I already said that having such an F would worry me, but "if F is computable, H is not secure" is a strong statement and I'm wondering whether it's backed up by math, not-quite-math-but-good-reasoning, or handwavy bluster. Please don't take this as an attack, though - I appreciate the attempt!
I don't think I'm able to make a much more rigorous argument, but I will note that you seem to be applying two different criteria here. If you want to criticize modeling a hash function as a PRF as too idealized, then you aren't going to get a mathematical answer (since it will start with "let H be a PRF").
A maximally strong mathematical answer is showing that given that F and H(a), we can reconstruct too much about a, for any H and corresponding F. There are probably other similarly strong forms of argument - I'm not saying that's the only one - but you can see how it differs from "Well, it's just not random."
Another possibility would be that they compute and send both H(a) and H(firsthalf(a)), if fisthalf(a) == secondhalf(a). That would work with any hash function, but I think would not appreciably increase security.