Hidden Inversions (Cops' Thread)

35

This is a puzzle the robbers' thread can be found here.

Your task will be two write two programs (or functions) such that they are anagrams of each other and one performs the left inverse of the other. These programs may accept and output as many integers or complex numbers as you wish. If you choose take numbers as character points or any other reasonable means you must indicate you are doing so in your answer. If you choose to restrict the domain of your function you must also indicate the restricted domain in your answer.

You will then present the first program in the form of an answer with left inverse hidden for robbers to find.

The shown program must implement a injective function (otherwise it would be impossible for a hidden answer to exist).

If your answer has not been cracked in one week you may reveal the hidden answer and mark it as safe. Safe answers cannot be cracked by robbers and will remain un-cracked indefinitely.

The goal will be to create the shortest un-cracked answer in bytes.

Example

You could show the following python program that adds one to the input

lambda x:~-x

A solution could be:

lambda x:-~x

This subtracts one from the input

Post Rock Garf Hunter

Posted 2017-01-16T14:17:21.913

Reputation: 55 382

Can we have imaginary/complex integers? – Stewie Griffin – 2017-01-16T16:18:45.177

@stewie if you indicate so you may – Post Rock Garf Hunter – 2017-01-16T16:20:34.113

1Is anagramming defined as permuting the characters, or permuting the bytes (in languages which don't use a single-byte character set)? – None – 2017-01-16T16:57:25.003

>

  • "You will then present one of the programs" seems to suggest that we can choose which to present, but the sentence continues "with left inverse hidden", implying that we have to present a specific one. Which is it? 2. The question specifically states "program" and doesn't appear to permit functions, but the example is a function rather than a program. Which is it?
  • < – Peter Taylor – 2017-01-16T17:01:27.570

    Does capitalisation matter? – user41805 – 2017-01-16T17:03:50.940

    @ais523 permuting bytes – Post Rock Garf Hunter – 2017-01-16T17:23:14.030

    @KritixiLithos To be anagrams the bytes should be the same. – Post Rock Garf Hunter – 2017-01-16T17:24:26.073

    @KritixiLithos By default, yes.

    – Martin Ender – 2017-01-16T17:43:58.693

    Is it a problem if f(g(x)) is potentially not exactly x due to floating point rounding, or would that be considered violating the injective function requirement? – SLuck49 – 2017-01-18T14:08:28.010

    @SLuck49 I believe that it is a meta consensus that floating point errors in the final answer are fine. However if you are rounding on top of the floating point error (causing your answer to be wrong) I would consider that a violation of the requirements. – Post Rock Garf Hunter – 2017-01-18T14:12:13.043

    Answers

    12

    Python 3, 80 bytes (Cracked)

    bhmq = int(input())
    print(bhmq ** 2)
    (1 or [(sqrt),(specification+of*integerr)])
    

    Domain: positive integers. Function is just squaring of a number. Input to stdin, output to stdout, as well as in the inverse function. Note that Python ignores the third line here, because it is syntactically valid and 1 is already a truthy value, so Python doesn't even look whether the right part of 'or' is well-defined.

    Robbers should write a sqrt function that will work correct on all non-zero squares, printing integer value as is, without floating point (so on input '4' output should be '2' or '2\n', not '2.0' or '2.0\n').

    Wolfram

    Posted 2017-01-16T14:17:21.913

    Reputation: 231

    1I like this one. It is deceptively difficult to crack – Post Rock Garf Hunter – 2017-01-18T00:22:27.630

    3Welcome to ppcg! Nice first post! – Rɪᴋᴇʀ – 2017-01-18T01:03:51.150

    Just to clarify, the inverse must also work correctly for something that's too big for floating point, like 15831049540459311999115956046667536? If not, I cracked it.

    – orlp – 2017-01-18T05:16:46.107

    1Nevermind on that crack, I messed up. The question still stands though. – orlp – 2017-01-18T05:33:09.357

    @orlp, although generally it is a hint, but I'll say that theoretically it works on any positive square (so don't assume presize floats) but practically it isn't feasible for such a big number. – Wolfram – 2017-01-18T07:51:22.317

    Which version should I consider "Python 3"? I see there are different features I could use depending on the specific version. Is it "any Python 3.x"? – G B – 2017-01-18T15:50:01.957

    If we assume that the robber program must have the characters from import*\nprint(int(input())), then the only valid imports are re,io,errno,abc,site,string,ast,org,os,stat for Python 3.5.2. I take it back, it might not be a complete list, because fractions would work. Anyway, there's no additional m for math. Is there a way to do an import without from that doesn't use a .? – mbomb007 – 2017-01-18T15:50:55.840

    I think my program works in any Python 3, but I don't know Python versions quite well to tell this for sure. If you'll use some features only from new versions (including 3.6), that will be great and this solution should be accepted, but I don't think it's possible to come up with such. – Wolfram – 2017-01-18T16:03:12.837

    I don't think we need any import. Well, actually, I don't think I am going to crack it anyway. My question is really "can we use the cmp() function which is only available in python 3.0.0?" – G B – 2017-01-19T07:08:09.097

    1I'd say 'no', if I'm really allowed to put this restriction by the rules of the challenge. – Wolfram – 2017-01-19T17:04:55.823

    @Wolfram You can restrict the version of python to whatever version you are running yourself. (run python3 --version to find out if you don't know) So unless your intended solution only works in python3 version 3.0.0 you can prevent people from using cmp(). – Post Rock Garf Hunter – 2017-01-19T20:38:33.407

    1Cracked? – Zgarb – 2017-01-20T09:05:34.740

    @Zgarb You got it, congrats :) (Only I didn't noticed one can glue 'for' and '2' together, so 1 bit more here.) – Wolfram – 2017-01-20T14:19:04.947

    @Wolfram Ah, I miscounted the spaces. Fixing now for completeness. – Zgarb – 2017-01-20T14:21:49.093

    11

    Python 3, 46 bytes, cracked

    lambda x:x*(1999888577766665//844333333222200)
    

    Doubles the input.

    Lynn

    Posted 2017-01-16T14:17:21.913

    Reputation: 55 648

    3How does 'Python' work in cops 'n robbers? May we choose an arbitrary version to attack your answer with? – orlp – 2017-01-16T15:04:05.147

    Oh, this is Python 3 specifically, sorry. So / is float division. – Lynn – 2017-01-16T15:05:24.780

    3Well, you just proved this challenge is not worth my time. Moving on. – mbomb007 – 2017-01-16T15:14:37.440

    5

    Cracked: http://codegolf.stackexchange.com/a/107020/18535

    – G B – 2017-01-16T15:25:52.027

    11

    7, 9 bytes, Cracked

    This program's full of nonprintable characters, so here's a hexdump:

    00000000: 2573 dc01 7e13 dcb6 1f                   %s..~....
    

    Note: this uses a numeric input routine that's incapable of inputting negative numbers, so this submission is restricted to nonnegative integers only.

    One problem with challenges is that you don't write explanations of the code (to make it harder to crack). On the other hand, this means that I don't have to go to to the trouble here.

    I picked 7 as the language because, especially in its compressed notation, it's pretty hard to read, and I don't see why it should be only me who has to go to the trouble of moving around 8-bit chunks of programs written in a 3-bit encoding. Good luck!

    Explanation

    Now that the program's been cracked (by brute force, unfortunately; that's always a danger in these short solutions), I may as well explain what I was getting at. This was actually fairly solvable by reading the program; I could have made it much more difficult, but that felt like a bad idea when brute-force cracks exist.

    We'll start by representing the program in a more natural encoding. As usual, bolded numbers indicate commands that run immediately (not all of which are representable in a program; 6 and 7 are but 2 to 5 aren't), unbolded numbers represent their escaped equivalents (0 to 5, all of which are representable in the original program; note that 0 is an escaped 6 and 1 is an escaped 7):

    11271734002770236713303
    

    The set of commands available in a 7 program source mean that it's basically just a literal that represents the original stack (there's nothing else you can do with just escaped commands, 6 and 7). So the first thing a program will do is push a bunch of stuff onto the stack. Here's how the stack looks after the program's run (| separates stack elements, as usual in 7):

    772|7|34662|023|73363
    

    The final stack element then gets copied to become the code to run (while remaining on the stack). As it happens, this is the only part of the program that's code; everything else is just data. Here's what it translates to:

    73363
    7      Push an empty element onto the stack
     3     Output the top stack element, discard the element below
    73     Combined effect of these: discard the top stack element
      3    Output the top stack element, discard the element below
       6   Escape the top stack element, then append it to the element below
        3  Output the top stack element, discard the element below
    

    In other words, this is mostly just a bunch of I/O instructions. Let's analyse this in detail:

    • 73 discards the 73363 that's still on top of the stack.
    • 3 outputs the 023, and discards the 34662. It can thus be seen that the 34662 is a comment, which was used to store the bytes needed in the other version of the program. As for what 023 does when output, it selects I/O format 0 (integers), then 23 is a directive which requests the implementation to input an integer (in 7, you do input via outputting specific codes that request input). The input is done by making copies of the stack element below, e.g. if the input integer is 10, the next stack element (currently 7) will become 7777777777. Thus, we're accepting input from the user in decimal, but it's being stored as unary.
    • 6 escapes the top stack element (changing each instance of 7 to 1; this is how strings consisting entirely of 7s are escaped), then appends it to the stack element before (772). So our data is now something like 7721111111111.
    • Finally, 3 outputs the stack element in question (and pops a blank stack element that's part of the default initial stack). Its value is calculated by taking the number of 1s and 7s, and subtracting the number of 0s and 6s. (The 2 in the middle is ignored in most cases; if it's at the end of the string, it'll become a trailing newline instead of being ignored, but PPCG rules don't care about that.) Thus, the output is the original input plus 2.

    At this point, there's nothing useful on the stack and nothing in the program, so the program exits.

    How do we reverse this? It's a simple matter of changing the 11 to 00, so that we're prepending characters to the input that make it 2 lower, rather than 2 higher. There's a 00 conveniently hidden eight octal digits further on in the program (so that octal digits and bytes line up with each other), so we can simply swap it with the 11 at the start.

    user62131

    Posted 2017-01-16T14:17:21.913

    Reputation:

    Cracked: http://codegolf.stackexchange.com/a/107103/18535

    – G B – 2017-01-17T14:00:41.353

    Side note: you don't have to explain your code, but knowing what your program does would be nice. – G B – 2017-01-17T14:01:15.313

    @GB: I gave a full explanation of the program (including an explanation of how the crack works). – None – 2017-01-17T20:02:27.323

    7

    JavaScript (ES6), 21 bytes, Cracked

    This is an easy one.

    b=>Math.pow(b,torc=3)
    

    Returns the cube of the input.

    Arnauld

    Posted 2017-01-16T14:17:21.913

    Reputation: 111 334

    1Cracked – Emigna – 2017-01-16T16:05:23.667

    6

    Python 2, 83 bytes, cracked

    #((()))****+,,---/2289;==oppppppqqqqqw~~
    lambda n:pow(n,65537,10998167423251438693)
    

    This is similar to my other answer. However, this uses 64-bit RSA, and is cryptographically quite weak. If you can rob this answer, you can theoretically rob my other one as well, given enough time.

    orlp

    Posted 2017-01-16T14:17:21.913

    Reputation: 37 067

    4Cracked. – Ilmari Karonen – 2017-01-16T18:53:38.620

    5

    JavaScript (ES6), 46 bytes, Cracked

    x=>Math.log(x+(+String(t=985921996597669)[5]))
    

    This function returns ln(x+1) where x is a non-negative number.

    Usage

    (x=>Math.log(x+(+String(t=985921996597669)[5])))(5)
    

    Note: Due to the nature of floating point numbers f(g(x)) may not exactly equal x. Example: f(g(4))=3.9999999999999996

    SLuck49

    Posted 2017-01-16T14:17:21.913

    Reputation: 901

    Cracked. That was really fun :-) – ETHproductions – 2017-01-20T15:27:01.523

    5

    Python 2, 47 bytes, Cracked

    lambda x:x**2or (iron() and saxifrage.extend())
    

    The domain for this function is {x ∈ ℤ | x > 0}. It squares its input.


    nmjcman101 found the intended solution:

    lambda x:sorted(a**2for a in range(x)).index(x)

    Post Rock Garf Hunter

    Posted 2017-01-16T14:17:21.913

    Reputation: 55 382

    1Haha, love the made up function calls – FlipTack – 2017-01-18T22:41:38.223

    1Cracked That was fun, I got stuck on the sorted anagram I had left! – nmjcman101 – 2017-01-19T20:32:33.603

    4

    J, 8 bytes, cracked

    Another simple one to start off with.

    [:]+:[-:
    

    Doubles the input.

    miles

    Posted 2017-01-16T14:17:21.913

    Reputation: 15 654

    How do we test this code? – user41805 – 2017-01-16T18:59:46.417

    @KritixiLithos https://tio.run/nexus/j#@x9tFattFa1r9f8/FwA

    – kaine – 2017-01-16T19:11:23.700

    1Cracked. – Conor O'Brien – 2017-01-16T19:12:10.453

    4

    Processing.js, 59 bytes, Cracked!

    float igetuwebaoli(int p){return p*(((17*-4*-3)))+0+0;}//,,
    

    This function multiplies the input by 204 (17*-4*-3=204). It takes in an int as input and outputs a float. As expected, the inverse divides the input by 204.

    An online interpreter for processing-js can be found here.

    user41805

    Posted 2017-01-16T14:17:21.913

    Reputation: 16 320

    1Cracked. – Ilmari Karonen – 2017-01-16T20:01:54.573

    4

    Processing (java), 59 bytes, SAFE

    float igetuwebaoli(int p){return p*(((17*-4*-3)))+0+0;}//,,
    

    This function multiplies the input by 204 (17*-4*-3=204). It takes in an int as input and outputs a float. As expected, the inverse divides the input by 204. Note: both programs take an int as input and output a float.

    This answer is exactly the same as my other answer, except that my other answer was written in Processing.js. Meet Processing-java, the less verbose cousin of Java. You can download Processing here at processing.org.

    The Crack

    float ap(int i){return i*pow(blue(get(0,0)),-1);}//++7*4*-3
    

    This program divides the argument by 204. But how? Let's go inside the function.

    i *                              //multiply i by
             blue( get(0, 0) )       //this (evaluates to 204)
        pow(                  , -1)  //raises to the -1 power (ie its reciprocal)
    

    Simple enough, but how does blue( get(0, 0) ) become 204? This is the centrepiece of this submission. First of all, get(0,0) gets the colour of the pixel located at (0,0) (the top left corner of the window, which always opens in a Processing sketch). Next, blue() gets the blue value of that pixel, which is 204!

    To come up with this submission, I experimented by printing the different attributes of the colour obtained by get(0,0). I have found out that the red, green, blue, alpha values are 204, 204, 204 and 255 respectively. From this, I decided to do a simple operation with this number and ended up with this post.

    user41805

    Posted 2017-01-16T14:17:21.913

    Reputation: 16 320

    I thought Kotlin was the less verbose cousin of Java! I do concede that the C family of languages is pretty big... but what would the family tree actually look like...

    – CAD97 – 2017-01-17T07:52:56.193

    I believe you made it, no one has cracked your post and it's been a week. – miles – 2017-01-24T14:59:49.013

    4

    J, 10 bytes, cracked

    1%~<:[@*>:
    

    Another simple one. Returns n2-1.

    miles

    Posted 2017-01-16T14:17:21.913

    Reputation: 15 654

    1

    Cracked: http://codegolf.stackexchange.com/a/107106/18535

    – G B – 2017-01-17T13:48:27.183

    4

    JavaScript (ES6), 15 bytes, cracked by Emigna

    t=>(!!0+~~t+~0)
    

    This functions returns n-1.


    You can test it like:

    (t=>(!!0+~~t+~0))(6)
    

    Cracked

    My intended solution is a bit different than Emigna's crack:

    t=>t+(+!!~~~00)

    insertusernamehere

    Posted 2017-01-16T14:17:21.913

    Reputation: 4 551

    2Cracked – Emigna – 2017-01-17T12:01:12.730

    4

    J, 29 bytes (Cracked by miles)

    5#.[:,(3 5&#:(-$]-)7)#.inv"0]
    

    This is a verb that takes a positive integer as input, and does the following:

    1. Convert to bases 2 and 4.
    2. Pad the base-4 representation with 0s to have the same length as the base-2 representation.
    3. Concatenate the two representations (base-2 first).
    4. Interpret the concatenation as a base-5 representation and convert to integer.

    Try it online!

    My solution

    The logic is pretty much the same as in the crack. The rank conjunction " can be stuck in many different places (and I use it to get rid of the unnecessary 0 and 3), since it doesn't really do anything in the solution.

    (7-5)#.[:(]-:&#$,)5#.inv"0 3]
    

    Zgarb

    Posted 2017-01-16T14:17:21.913

    Reputation: 39 083

    I don't understand J, but my experiments show this actually takes integer in bases 2 and 4, adds zeros to the end of base 4 to make their length equal, and only then concatenates. Are these zeros intended? – Wolfram – 2017-01-18T09:07:45.870

    @Wolfram The zeros are intended, that's what I tried to say with "simultaneously". Otherwise I don't think it would be reversible. – Zgarb – 2017-01-18T09:09:35.777

    @Wolfram I added a more explicit description. – Zgarb – 2017-01-20T09:11:34.067

    Cracked. – miles – 2017-01-23T13:56:38.913

    3

    Brain-Flak, 26 bytes, Cracked

    Original

    ((((()()())){}[()]){}{}{})
    

    My Crack

    ([(((()())){}()){}{}()]{})

    1000000000's Crack

    ([(((()())()){}){}{}](){})

    Post Rock Garf Hunter

    Posted 2017-01-16T14:17:21.913

    Reputation: 55 382

    1Cracked – 0 ' – 2017-01-16T18:32:35.203

    3

    JavaScript (ES6), 63 bytes Cracked by Ilmari Karonen

    x=>eval(atob`eCp4KzEvLyAgfXBModLS4TvEn4wp1iys9YRRKC85KLIhNMC=`)
    

    Time for some atob nonesense. This function returns x*x+1 where x is a non-negative number.

    Usage

    (x=>eval(atob`eCp4KzEvLyAgfXBModLS4TvEn4wp1iys9YRRKC85KLIhNMC=`))(5)
    

    Intended

    x=>eval(atob`Lyp5fMRwICAgKi9NYXRoLnBvdyh4LTEsMC41KS8veCp4KzE=`)

    There's a large number of potential solutions, but I was hoping that the leading characters would throw off the byte order enough to make this harder. C'est la atob

    SLuck49

    Posted 2017-01-16T14:17:21.913

    Reputation: 901

    Cracked. – Ilmari Karonen – 2017-01-17T22:54:22.340

    Did you just accidentally repost your challenge code as the intended solution? :) – Ilmari Karonen – 2017-01-18T16:45:44.617

    @IlmariKaronen Thanks, that'll teach me to copy/paste... lol yeah right :P – SLuck49 – 2017-01-18T17:02:58.383

    2

    Python 2, 225 bytes, cracked by Sp3000

    #((()))****+,,---/000555666888;==oppppppqqqqqw~~
    lambda n:pow(n,65537,9273089718324971160906816222280219512637222672577602579509954532420895497077475973192045191331307498433055746131266769952623190481881511473086869829441397)
    

    Domain of this function is [0, n), where n is the huge number above. Yes, this function is invertible on this domain. And unless I messed up, breaking this answer is as hard as breaking 512 bit RSA.

    orlp

    Posted 2017-01-16T14:17:21.913

    Reputation: 37 067

    1Brute-forcing this is considerably easier than brute-forcing RSA because you already have an approximate anagram of the constant you need. On the other hand, it's likely still too difficult to manage in practice. – None – 2017-01-16T17:29:23.783

    @ais523 If you are interested, check out my other answer. It should be manageable. – orlp – 2017-01-16T17:38:15.640

    4

    Keep in mind that there is a meta post regarding randomisation in CnR challenges: http://meta.codegolf.stackexchange.com/questions/10793/add-randomization-in-cnr-posts-as-a-loophole

    – user41805 – 2017-01-16T18:21:34.063

    5@KritixiLithos My answer does not contain randomization, hashes or builtin crypto code. It's literally one modular exponentiation. – orlp – 2017-01-16T18:25:41.333

    2Your answer intendedly aims at a problem known to be hard to solve and therefore matches the meta post (especially since it mentions RSA directly). I think that even if you meta loophole your script still deserves my downvote. – Christoph – 2017-01-20T13:54:42.183

    4Cracked – Sp3000 – 2017-01-22T09:33:10.693

    If it requires brute-forcing to solve, it's not in the spirit of the challenge. – mbomb007 – 2017-01-23T15:05:06.047

    0

    J, 15 bytes

    (".&,'10.')#.#:
    

    Takes a non-negative integer n, converts it to a list of binary digits, and combines those digits as a base 10 number.

    Try it online!

    miles

    Posted 2017-01-16T14:17:21.913

    Reputation: 15 654