how on earth does openssh not only have incredibly fucked versioning but is the only package i've ever seen to mention a "privilege separation" chroot path which actively breaks non-root builds. are you fucking kidding me bruh. "privilege separation chroot" defaulting to /var/empty and it immediately errors if it can't create it????? why are your version strings like that bruh?????
if the buckets are 1 bit in size and each maps to 1 bit of the input and your hash function is the identity function you get a trie
and tries are literally the best data structure ever
ok actually here's a hot take i just made up and sounds good
so python's def __hash__(self) -> int API is obviously incredibly fucking annoying:
- because python doesn't generally use
intlike C and bit operations are extremely tedious - you absolutely do not have any concept of "plain old data" or converting objects to data through casts like C
you can't recursively invoke hash(self.field) in any useful way unlike every single other dunder, because:
- python absolutely has fixnums with stable implementation semantics, but PYTHON FUCKING HATES ITS USERS so we get this shit instead: https://docs.python.org/3/reference/datamodel.html#object.__hash__
Note:
hash()truncates the value returned from an object’s custom__hash__()method to the size of a Py_ssize_t. This is typically 8 bytes on 64-bit builds and 4 bytes on 32-bit builds. If an object’s__hash__()must interoperate on builds of different bit sizes, be sure to check the width on all supported builds. An easy way to do this is withpython -c "import sys; print(sys.hash_info.width)".
this is a work of art, a passionate expression of expertise. nobody does it like cpython. in reverse order:
- they hit you with the yung
python -cfor two reasons:- discourages any helpful PR adding a crossref linking to
sys.hash_info, or (even worse) describing the contents of thehash_infostruct. that way it's less obvious when arch linux backdoors its users - implies you should be executing this on the command line and then trusting the result is the same elsewhere. NOBODY USES
pythonANYMORE SINCE YOU NEGGED THEM TO WRITEpython3!!!! i can't be sure of the implications of that - actually wait this is even more fucked because they're telling you to "check the width on all supported builds" which is actively just fucking WRONG the value is NOT going to be accurate unless you JUST FUCKING USE THE VALUE FROM THE CURRENT INTERPRETER ENVIRONMENT
- discourages any helpful PR adding a crossref linking to
but the first line is just a masterpiece:
- "truncates the value": what is "truncating" an integer. the user will likely assume taking the N least significant bits from an arbitrary-length binary string. but cpython has its own bigint mechanism, which i'm pretty sure does not specify a byte representation
- in c extensions and the cpython implementation you have to call a function with a weird name i recall having difficulty finding. iirc there's no function in the C API to specify any range restrictions and definitely not bit width restrictions. if you don't know whether it's out of fixnum range i believe they tell you to write it to a string. there is no "write this unambiguously" function, you have to invoke the python string formatting logic but in the C API that has a completely seperate syntax and semantics, specified typically via C string literal.
- "to the size of a
Py_ssize_t": this is of course the data type with 1/2 its range as negative values. does "size" refer to the maximum numeric value? does it refer to the bytes of the custom bigint representation? does it preserve the sign in a two's complement representation?
the subsequent clarification that the size of the size type is typically the size of a pointer answers none of those questions, but raises further ones
oh lol lmao in the configure.ac
AC_CHECK_SIZEOF([size_t], [4])
that's pretty good
there's also this incredibly suspicious ifdef typedef of Py_ssize_t in code that claims to check for atomics support. free vuln
ok so python sucks. it sucks terribly. however i think returning int would be a reasonable API for a lot of compiled languages
obviously it would be neat if the bit width were a compile-time generic instead. but i think you do have to be careful here, because the reason making your hash function conform to the standard mathematical definition of a hash function over bit strings is so that the user can meaningfully influence not just the collision rate "averaged" across "all" inputs (literally never defined), but how known ranges of inputs spread across the output bits
i was going to say "rust's type system literally can't do that API" but i think you can do fn hash<const N: usize>(&self) -> [u8; N] in a trait. you can't do const fn hash on stable, so you can't do this in a library, because rust fucking hates its users, but you can do it in a library inside google
anyway, what rust does instead is pretty great because it's deeply fucking mysterious, has a confusing and nonstandard signature, and absolutely 100000% ensures you cannot meaningfully influence which bits of output correspond to which bits of input
it's been several months since i last considered this problem and i'm delighted to find not only was i right before to say "cryptographic hashes are unnecessary computation for 100% of hash tables because the threat model is obviously fucked", but it's also now very clear to me that hash tables have COMPLETELY distinct goals for hashing than cryptographic message digests