PI window encryption

13

2

This is a simple encryption method that uses PI digits to encode a message, the method is simple:

The key is just a positive integer that indicates where the window starts then:

Given a string to encrypt, containing only lowercase letters, no spaces, you take its length, then you find the Nth digit of PI and then proceeds to shift every letter to the right for the amount indicated by the digit.

For example, if the key is 2 and I want to encode house, I take a window of 5 digits from the second one: 14159 and then it becomes:

h -> i
o -> s
u -> v
s -> x
e -> n

a.- Your program/function/algorithm will receive two parameters, an string composed only of lowercase letters with no spaces and the key, which will be just a positive integer between 1 (1 refers to 3) and 1000, which could be more or less as I'm not quite sure how long does it take to compute PI with said accuracy because:

b.- You must compute PI yourself in your code, here is a neat webpage to compare with: Pi Day. The input should never have you calculate PI beyond the 1000 digit, meaning that length(message)+key <= 1000.

By computing Pi, I mean not harcode it in your code (silly for a code golf) nor use any embedded constant in your code nor any trigonometric identity (2*acos(0)) nor any web reference.

c.- The output will be just the encrypted string.

This is a code golf question, shorter code wins!

I'll be accepting the winning answer at July 14th, 2014.

BrunoJ

Posted 2014-06-27T21:02:22.117

Reputation: 659

1What happens when letters are shifted past the end of the alphabet? Does wrap-around to the beginning of the alphabet occur or something else? – Digital Trauma – 2014-06-27T22:39:23.100

1Yes, you just start over from the beginning. – BrunoJ – 2014-06-27T22:51:22.960

6What counts as "compute yourself"? ArcCos(-1)? – Martin Ender – 2014-06-28T00:04:28.060

Please read this question and its comments very carefully. Then please edit your question to specify what you mean by "compute PI yourself"

– Digital Trauma – 2014-06-28T00:30:25.293

Is 3 the zeroth or the first digit of pi? – Digital Trauma – 2014-06-28T00:32:49.133

1I explained better what I wanted to say by computing it yourself and pointed that 3 is the first digit. – BrunoJ – 2014-06-28T01:09:04.577

Key 1 and the the string aaaaa will give dbebf with a = 0, b = 1, etc. By replacing the letters by the numbers, we can compute Pi by using the answers to this question. :-) – A.L – 2014-06-28T03:06:28.087

This is effectively two challenges whose scores you sum: computing digits of pi and doing Caesar shifts by a series of offsets. The first has been done, so I'd suggest just doing the second, perhaps by allowing the embedded constant pi. There has been a similar letter-shifting question though: http://codegolf.stackexchange.com/questions/678/decipher-a-vigen%C3%A8re-ciphertext

– xnor – 2014-06-28T03:21:10.987

1This actually seems like a really smart encryption algorithm, why isn't this widely used (except with a more complicated constant like e^pi or something less recognizable)? – ASKASK – 2014-06-28T22:55:18.780

@ASKASK you'd need trillions or maybe more digits of Pi to protect against brute forcing/dictionary attacks – Digital Trauma – 2014-06-29T01:30:29.553

Does the pi calculation need to have a reasonable runtime? Any bound on how many digits we might need to compute? – xnor – 2014-06-29T03:41:44.597

@DigitalTrauma Here is what I'm thinking: Along with the encoded message there is some sort of numerical key (maybe the date or something like that) which is passed into a function (ex: f(x)=e^(pi*x)) which generates a number of infinite digits that appear in no obvious order. The attacker would need to know the exact function to generate the number in order to know the pattern at which the letters were being shifted. How could a brute force/dictionary figure that out? – ASKASK – 2014-06-29T06:23:47.837

Any limit on the string length? – Aurel Bílý – 2014-06-30T12:30:11.363

Just addressed the string length more clearly and, as answers are already posted I don't think it's wise to split it into two challenges. – BrunoJ – 2014-06-30T15:07:15.473

Answers

3

CJam - 51

l_,li(2e4,-2%{2+_2/@*\/2e2000+}*Ab><]z{~+_'z>26*-}%

Example input:

zebra
20

Output:

dkdxe

This works for (string length) + key <= 2000, but is quite slow for the online interpreter (still fast with the java interpreter).

Here's a version that works up to 200 and you can try at http://cjam.aditsu.net/ without waiting too long:

l_,li(2e3,-2%{2+_2/@*\/2e200+}*Ab><]z{~+_'z>26*-}%

aditsu quit because SE is EVIL

Posted 2014-06-27T21:02:22.117

Reputation: 22 326

5

Python - 370

Ok, nice one, finally got the pi thing working with thanks to link1 and link2.

from decimal import *
def f(s,n): 
 j=len(s)
 getcontext().prec=j+n+5
 d=Decimal
 e=d(0)
 for k in range(0,j+n+5): 
  e+=(d(16)**(-k)*(d(4)/(8*k+1)-d(2)/(8*k+4)-d(1)/(8*k+5)-d(1)/(8*k+6)))
 c=`e`.split("'")[1].replace('.','')
 t=''
 for i,l in enumerate(s):
  o=ord(l)
  for v in[0,32]:
   if 64+v<o<91+v:
    l=chr(((o-65-v)+int(c[i+n-1]))%26+65+v)
  t+=l   
 print t

Example output:

>>> f('house',2)
isvxn

and another:

Wimt fcy d dnyh uhkvkv qhvadil   

>>> f('This was a very secret message',1)

Willem

Posted 2014-06-27T21:02:22.117

Reputation: 1 528

1

JavaScript - 167 173 176

Thanks to Michael for the clever representation of powers of 16.

This can calculate PI up to the 16-th digit.

function e(s,o){for(p=i=n=r='',m=1;s[+i];m<<=4,n>o?r+=String.fromCharCode(s.charCodeAt(i)-+-(1e15*p+'')[o+i++]):0)p-=(4/((d=8*n++)+1)-2/(d+=4)-1/++d-1/++d)/m;return r}

The test case:

> e("house",2)
"isvxn"

core1024

Posted 2014-06-27T21:02:22.117

Reputation: 1 811

What about m=1 and m<<=4 instead of m='0x1' and m+=0 ? Saves 3 bytes. – Michael M. – 2014-06-30T09:19:13.547

1

Python - 321 304 288 285

from decimal import*
d=Decimal
s,n=raw_input(),input()
l=len(s)
getcontext().prec=n+l
print''.join([chr((v-97)%26+97)for v in map(sum,zip(map(ord,s),map(int,str(sum([(d(4)/(8*k+1)-d(2)/(8*k+4)-d(1)/(8*k+5)-d(1)/(8*k+6))/16**k for k in range(0,l+n)])).replace('.','')[n-1:n+l])))])

Most of the golfed version is easy to read and understand. The final line is ungolfed below:

# Calculate PI using the BBP formula.
pi = 0
for k in range(0,l+n):
    pi += (d(1)/(16**k))*((d(4)/(8*k+1))-(d(2)/(8*k+4))-(d(1)/(8*k+5))-(d(1)/(8*k+6)))

# Remove the decimal point in PI.
pi = str(pi).replace('.','')

result = []
# For the ASCII sum of each pair of letters in `s` and its digit in PI 
for v in sum(zip(map(ord, s), map(int, pi))):
    result.append((v-97)%26+97)

# Convert all the ordinal values to characters
print ''.join(map(chr, result))

EDIT #1: simplified my module arithmetic.

EDIT #2: refactored the BBP formula.

BeetDemGuise

Posted 2014-06-27T21:02:22.117

Reputation: 442

0

Haskell - 265 267 bytes (no IO)

p=g(1,0,1,1,3,3)where g(q,r,t,k,n,l)=if 4*q+r-t<n*t then n:g(10*q,10*(r-n*t),t,k,div(10*(3*q+r))t-10*n,l) else g(q*k,(2*q+r)*l,t*l,k+1,div(q*(7*k+2)+r*l)(t*l),l+2)
e i s=zipWith(\k c->toEnum$fromIntegral k+fromEnum c::Char)(take(length s)$drop(fromIntegral$i-1)p)s

p is a golfed version of the algorithm that can be found at http://rosettacode.org/wiki/Pi#Haskell

e is the encoding function :

λ> e 2 "house"
"isvxn"

It does not loop around if an index is outside of the lowercase alphabet. This means that some other characters can slip in the encoded string :

"Sfufv#Kork(mq}nns j{i&sv&xitmujtu&vey|h{xljej|35.)(\"%(\"\"&\" %\"\"$()$ ''\"&'!)$'(\"&($(\"& !$'&)]hrs\"ow olih7$Tdkhnsj ns&qpdlw}oplwmxbipn#o{ur!vhbp\"mitj/"

Unfortunately, it takes several seconds with offsets greater than 10 000 to compute the output. Fortunately, when using the same offset multiple times, the digits only have to be computed the first time.

Bonus - Decoding

d i s=zipWith(\k c->toEnum$fromEnum c-fromIntegral k::Char)(take(length s)$drop(i-1)p)s

Again if we test with isvxn :

λ> d 2 "isvxn"
"house"

gxtaillon

Posted 2014-06-27T21:02:22.117

Reputation: 577

Made a typo in your bonus section. d 2 "isvsn" should be d 2 "isvxn" – Spedwards – 2014-06-30T08:47:22.790

Fixed. Thanks for noticing. – gxtaillon – 2014-06-30T09:44:49.787

0

CoffeeScript - 148 Chars/Bytes

My first ever Code Golf

Unfortunately It does not support wrapping (So a z would end up being punctuation)

e=(m,k)->(m.split('').map (v,i)->String.fromCharCode v.charCodeAt()+parseInt Math.PI.toString().replace('.','').slice(k-1,m.length+k-1)[i]).join('')

Demo on CSSDeck

Called with:

alert e 'house', 2

isvxn

ISNIT

Posted 2014-06-27T21:02:22.117

Reputation: 101

Did you read the whole question, as it clearly states that you are not allowed to "use any embedded constant in your code"? – core1024 – 2014-07-14T17:01:49.463