Before, invert_elligator would invert to a gf, which wouldnt be a uniformly
random string because, eg, curve25519 gfs only have 255 bits out of 256.
Now add a random multiple of p. This still wont work for future curves
that have a field size of 1 mod 8, because those curves use elligator with
no high bit set, but its a start
Currently compiles and passes tests on x86_64 with arch_32 and
DECAF_FORCE_32_BIT=1 (as well as the native settigs of course),
so that's a start.
Want to make serialization routine cross-arch. Need to check that
perf is good enough (likely). Current routine in p25519/arch_32
is almost cross-arch, but has known bugs (FIXMEs). Needs to take
into account separate p and, for NEON, the LIMBPERM.
Want to decouple arches for each curve/field. Currently the split
between decaf_word_t and word_t makes this fraught with peril. Fix
is probably to rename decaf_word_t to decaf_api_word_t and fix it
to either uint32 or uint64, then make internal things separate per
field. That way we don't have to try arch detection in the header,
which is nice.
Need to make decaf_gen_tables use SC_LIMB. Might as well get rid
of API_NS there too.
I'm kind of torn about this change, because it adds a bunch of
fairly complex code that's only needed for esoteric use cases,
and it makes Elligator more complex, if mostly only for testing
purposes. Basically, this is because Elligator is approximately
~8-to-1 when its domain is 56 bytes: 2 because it's [0..p+small]
instead of [0..(p-1)/2], and 4 for cofactor removal. So when you
call the inverse on a point, you need to say which inverse you want,
i.e. a "hint".
Of course, the inverse fails with probability 1/2.
To make round-tripping a possibility (I'm not sure why you'd need this),
the Elligator functions now return an unsigned char hint. This means
that you can call Elligator, and then invert it with the hint you gave,
and get the same buffer back out. This adds a bunch of complexity to
Elligator, which didn't previously need to compute hints. The hinting is
reasonably well tested, but it is known not to work for inputs which are
very "large", i.e. end ~28 0xFF's (FIXME. Or roll back hinting...).
There's also a significant chance that I'll revise the hinting mechanism.
Create functions:
decaf_448_invert_elligator_nonuniform
decaf_448_invert_elligator_uniform
decaf::Ed448::Point::invert_elligator
decaf::Ed448::Point::steg_encode
for inverting Elligator. This last one encodes to Point::STEG_BYTES = 64
bytes in a way which is supposed to be indistinguishable from random, so
long as your point is random on the curve.
Inverting Elligator costs about 2 square roots for nonuniform. For
uniform, it's just Elligator -> diff -> invert, so it's 3 square roots.
Stegging fails about half the time, and so costs about twice that, but
the benchmark underreports it because it ignores outliers.
The code is tested, but I haven't checked over the indistinguishability
from random (I've only proved it correct...). There could well be a way
to break the steg even without taking advantage of "very large" inputs
or similar.