Score:0

Given a safe elliptic curve with generator $g_1$. Is there a function $f:(g_1^a,g_1,a)\leftrightarrow g_2$? For random $g_3,g_4$ -> $a$ unknown

at flag

In use-case we have a (random) generator $g_1$ and perform operations $g_1^{a}$ for known $a$ inside a safe elliptic curve modulo $p$.

Is there any function $f$ which gives us a new (most likely different) generator $g_2$ out of $g_1$ and $a$: $$f(g_1,a) = g_2$$ and the inverse given a generator $g_2$ (which can also be random) deliver us a generator $g_*$ and an exponent $a_*$: $$f^{-1}(g_2) = (g_*,a_*)$$ $$(g_{*},a_*) \in \{ f(g_{°},a_{°}) = g_2\}$$ So $f^{-1}$ only need to deliver one combination $g_*,a_*$ out of all $g_°,a_°$ with $f(g_°,a_°) = g_2$.


About security:

For such $g_1,a,g_2$ it should be infeasible to compute $b$: $$g_1^b \equiv g_2 \mod{p} \text{ (the elliptic curve)}$$ or computing $a_2$ (also true for random $g_1,g_2$): $$g_1^{a} \equiv g_2^{a_2} \mod{p}$$ Given random generators $g_3,g_4$ it should be infeasible to find $a_3$: $$f(g_3,a_3) = g_4$$

The amount off different solutions for all parameter $|\{f(g_°,a_°)\}|$ and $|\{f^{-1}(g_°)\}|$ should be as big as possible.


Special cases:

It would be nice if those $g$ are always generators of the max (prime) cycle length and $a > 2^{200}$ ($f^{-1}$ of a random $g$ (with max cycle length)) in elliptic curve modulo $p > 2^{220}$. But if I'm not mistaken we should almost always get a long enough cycle length and a big enough $a$ if we allow all results. ($p = n_s \cdot p_l +1, n_s\ll p_l$)


All operations including calculation of $f,f^{-1}$ are applied at the local device. The relations noted in security-section should still be unknown for everyone.

poncho avatar
my flag
$f^{-1}(g_2) = (g_1,a)$; if $q$ is the order of the group, then there are $q$ possible inputs and more than $q$ possible pairs of $g_1, a$. Do you mean that all this inverse operation is required to do is find some $g_1, a$ pair s.t. $f(g_1, a) = g_2$ and not necessarily the same $g_1, a$ pair originally used to generate $g_2$?
J. Doe avatar
at flag
@poncho Oh, you are right. Rewrote it. And yes the inverse only need to find some $g_{*},a_*$ with $f(g_{*},a_*) = g_2$ Don't need to be the same.
Richard Thiessen avatar
mx flag
Something like the elligator map might help here https://elligator.org/map. It should be straightforward to compose such a mapping with some additions or subtractions in either the scalar or point domain to implement $f()$ and $f^{-1}()$. $f^{-1}()$ requiring choosing from $q$ possible $f()$input pairs. One problem is half the EC points can't be mapped to scalars.
J. Doe avatar
at flag
@RichardThiessen thanks for the hint but I haven't found a way to define $f, f^{-1}$ yet. $f$ with input generator $g=(g_x,g_y)$ (on the elliptic curve) and the current scalar exponent $a$ should lead to a new generator $g'$ as output. In this direction it is not so important if only half (or similar) work. $f^{-1}$ only has a generator $g'$ as input and delivers a generator $g$ and a scalar $a$ as output. This should always be defined. So in total $f$ maps 3 scalars to 2 with the first two on each side laying at the EC. The linked mapping only maps 1 scalar to 2 which lay at the EC.
Score:1
mx flag

This turns out to be quite simple. We define a reversible permutation f(G,a)-->(G',a') that is a permutation on the set of all (G,a) pairs. The function can be the forward permutation with the a' discarded. The inverse function is the reverse permutation with the a' value set to either a fixed, random, or chosen value.

We define two functions, hash_P2s(P)=s and hash_s2P(s)=P, which take either a point P or a scalar s and pseudorandomly map it to the other type of thing.

The first can be as simple as:

def hash_P2s(P):
    h=sha512(curve.encode(P))
    return bytes_to_int(h)%curve.order

The second (hash to curve) is covered by this IETF document. The simplest option here is to generate random encoded points until one is valid.

Any good hash to curve function generates points whose discrete log is unknown.

def hash_s2P(s):
    i=0
    while 1:
        h=sha512(s2bytes(s)+i.to_bytes(4,"little"))
        #truncate to correct length
        candidate=h[:EC_POINT_ENCODED_LEN]
        #if the result is a valid point, we're done
        if curve.is_valid_point(candidate):
            return curve.decode(candidate)
        #increment and try again
        i+=1

Finally, we put these together into a Feistel-like permutation where a point and a scalar are used to generate another (point,scalar) pair.

def f(G,a):
    G=curve.add(G,hash_s2P(a))
    a=(a+hash_P2s(G))%curve.order
    G=curve.add(G,hash_s2P(a))
    return G,a

The output a value can be discarded but if fed into the inverse function the original (point,scalar) pair will be produced.

def f_inverse(G,a):
    G=curve.sub(G,hash_s2P(a))
    a=(a-hash_P2s(G))%curve.order
    G=curve.sub(G,hash_s2P(a))
    return G,a

If you feed an output G and a random scalar into the inverse function you'll get a random (G,a) input pair of course.

preventing non-generator outputs

The input and output domains of the permutation include all valid points including the zero point which is not a generator. An attacker can find $(G,a)=f^{-1}(0)$ which when run through the function give a non-generator.

One easy way to solve this is to map the zero point to something else at the end of f(). The inverse function won't care since it's not necessarily deterministic.

Security

This is similar to a Feistel network in that we take some state split into two parts (G,a) and use pseudorandom functions that map between the part domains to alternately modify each side.

The GaG modification sequence ensures the function cannot be solved to find a f(G,a)=xG DLOG relation. aG and aGa both allow an attacker to find such a DLOG relationship trivially. GAG is the smallest sequence that does not without a birthday type attack in the point or scalar domain which is as hard as just solving the DLOG problem directly.

J. Doe avatar
at flag
thanks for the answer(?). Will need some more time thinking about it before marking it as one. `GaG` is a nice idea. But it need to be deterministic. No (real) random is involved. Each user will get the same results every time. So for $f^{-1}$ it will be a constant $a=1$ or $0$.
J. Doe avatar
at flag
But being deterministic would not change anything about the security, right?
Richard Thiessen avatar
mx flag
Nope, you can obviously just fix the `a'` input to some arbitrary value.
Richard Thiessen avatar
mx flag
No impact on security.
J. Doe avatar
at flag
Thanks again! EC was just one variant of a solution for a more general problem. This `GaG` method should also work for other encryption algorithms or more specific AES. This would be easier and faster to compute and requires a lower bit size for security. Only downside would be duplicates starting from one element. Will do some new question about this. Also tried around with hash functions solving this problem. I'm little gloomy not finding it by myself. (just for record: [question of more general problem](https://crypto.stackexchange.com/questions/107277) (deleted bc not needed anymore) )
Richard Thiessen avatar
mx flag
It is **very important** here that the domain of `G` and `a` are very large (~2^256). While this approach to defining a permutation is common in format preserving encryption, when the domain of the two halves is small, you will need more rounds, Even with two halves of 128 bits each, that still allows for meet in the middle attacks using 2^64 work. Three rounds then is insufficient.
J. Doe avatar
at flag
what is a 'round' in this context? I only know it from block cipher like AES. Or is it applying the $f$ function multiple times in a row? But I don't see how this would increase the security. For AES `G` would be the 128-bit message and `a` the 128-bit key. Only thought about forward direction. Starting from one point each we could do meet in the middle to find a common `G` but we would have most likely a different `a`. Same `a` as well should take $2^{64}$ longer. But you are right if we use $f^{-1}$ there we only need $ 2^{64}$ steps to find a common ancestor. Too sad
Richard Thiessen avatar
mx flag
A round in the context of a [Feistel cipher](https://en.wikipedia.org/wiki/Feistel_cipher) means a single pseudorandom function and addition. `GaG` is three rounds. AES does not work in any way like the construct I laid out here. As you've seen when working with 128 bit values, finding collisions is practical. [Format preserving encryption](https://en.wikipedia.org/wiki/Feistel_cipher) requires more back and forth rounds to get closer to the ideal of a pseudorandom permutation since the domain of the two state variables is smaller.
J. Doe avatar
at flag
But lets assume we do more rounds and have an ideal pseudorandom permutation. With 128-bits we could still meet in the middle after $2^{64}$ steps (in mean). This `GaG` method for AES(block,key) would be $G = AES(G, hash(a)); a += hash(G); G = AES(G,hash(a))$. Despite not working for 128-AES it should work for a 256 bit block cipher. (only a small amount of keys $a$ are allowed in each step)
Richard Thiessen avatar
mx flag
Let us [continue this discussion in chat](https://chat.stackexchange.com/rooms/147345/discussion-between-richard-thiessen-and-j-doe).
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.