Q:

Obfuscating text by cycling ternary digits

The goal of this challenge is the write the shortest function/program to take input text, encrypt it using the method below, and return the result.
As an example, I will use the string hello world.
First, get the input text.
hello world

Second, convert the string into ternary (base 3). Use this key:
a = 000
b = 001
c = 002
d = 010
e = 011
f = 012
g = 020

...

w = 211
x = 212
y = 220
z = 221
[space] = 222

With this key, hello world becomes 021011102102112222211112122102010, as seen below.
 h   e   l   l   o       w   o   r   l   d
021 011 102 102 112 222 211 112 122 102 010

Third, move the first digit to the end.
021011102102112222211112122102010
becomes
210111021021122222111121221020100

Fourth, convert the number back into a string using the same key.
210 111 021 021 122 222 111 121 221 020 100
 v   n   h   h   r       n   q   z   g   j

Lastly, return the encrypted text.
vnhhr nqzgj

Here are some sample text and their output:
the turtle ==> dvo fh ego
python ==> uudwqn
code golf ==> hpjoytqgp
As this is code golf, the shortest entry in bytes wins.
Errors are allowed if some of the characters are not lowercase letters or space.
This is my first challenge, so any suggestions would be more than helpful.
Good luck!
Leaderboard:

var QUESTION_ID=54643;function answersUrl(e){return"http://api.stackexchange.com/2.2/questions/"+QUESTION_ID+"/answers?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+ANSWER_FILTER}function getAnswers(){jQuery.ajax({url:answersUrl(page++),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){answers.push.apply(answers,e.items),e.has_more?getAnswers():process()}})}function shouldHaveHeading(e){var a=!1,r=e.body_markdown.split("\n");try{a|=/^#/.test(e.body_markdown),a|=["-","="].indexOf(r[1][0])>-1,a&=LANGUAGE_REG.test(e.body_markdown)}catch(n){}return a}function shouldHaveScore(e){var a=!1;try{a|=SIZE_REG.test(e.body_markdown.split("\n")[0])}catch(r){}return a}function getAuthorName(e){return e.owner.display_name}function process(){answers=answers.filter(shouldHaveScore).filter(shouldHaveHeading),answers.sort(function(e,a){var r=+(e.body_markdown.split("\n")[0].match(SIZE_REG)||[1/0])[0],n=+(a.body_markdown.split("\n")[0].match(SIZE_REG)||[1/0])[0];return r-n});var e={},a=1,r=null,n=1;answers.forEach(function(s){var t=s.body_markdown.split("\n")[0],o=jQuery("#answer-template").html(),l=(t.match(NUMBER_REG)[0],(t.match(SIZE_REG)||[0])[0]),c=t.match(LANGUAGE_REG)[1],i=getAuthorName(s);l!=r&&(n=a),r=l,++a,o=o.replace("{{PLACE}}",n+".").replace("{{NAME}}",i).replace("{{LANGUAGE}}",c).replace("{{SIZE}}",l).replace("{{LINK}}",s.share_link),o=jQuery(o),jQuery("#answers").append(o),e[c]=e[c]||{lang:c,user:i,size:l,link:s.share_link}});var s=[];for(var t in e)e.hasOwnProperty(t)&&s.push(e[t]);s.sort(function(e,a){return e.lang>a.lang?1:e.lang<a.lang?-1:0});for(var o=0;o<s.length;++o){var l=jQuery("#language-template").html(),t=s[o];l=l.replace("{{LANGUAGE}}",t.lang).replace("{{NAME}}",t.user).replace("{{SIZE}}",t.size).replace("{{LINK}}",t.link),l=jQuery(l),jQuery("#languages").append(l)}}var ANSWER_FILTER="!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe",answers=[],page=1;getAnswers();var SIZE_REG=/\d+(?=[^\d&]*(?:&lt;(?:s&gt;[^&]*&lt;\/s&gt;|[^&]+&gt;)[^\d&]*)*$)/,NUMBER_REG=/\d+/,LANGUAGE_REG=/^#*\s*([^,]+)/;
body{text-align:left!important}#answer-list,#language-list{padding:10px;width:290px;float:left}table thead{font-weight:700}table td{padding:5px}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b"><div id="answer-list"> <h2>Leaderboard</h2> <table class="answer-list"> <thead> <tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr></thead> <tbody id="answers"> </tbody> </table></div><div id="language-list"> <h2>Winners by Language</h2> <table class="language-list"> <thead> <tr><td>Language</td><td>User</td><td>Score</td></tr></thead> <tbody id="languages"> </tbody> </table></div><table style="display: none"> <tbody id="answer-template"> <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody></table><table style="display: none"> <tbody id="language-template"> <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody></table>

A:

Pyth, 23 22 bytes
sXc.<sXz=+GdJ^UK3K1KJG

Try it online: Regular Input / Test Suite
Thanks to @isaacg for one byte.
Explanation:
sXc.<sXz=+GdJ^UK3K1KJG
        =+Gd             append a space the G (preinitialized with the alphabet)
               K3        assign 3 to K
            J^UK K       assign all 3-digit ternary numbers 
                         [[0,0,0], [0,0,1],...,[2,2,2]] to J
      Xz  G J            translate input from G to J
     s                   sum (join all ternary numbers to one big list)
   .<             1      rotate by 1
  c                K     split into lists of size 3
 X                  JG   translate from J to G
s                        join chars to string and print

A:

Pyth, 26 bytes
J+Gds@LJiR3c.<s.DR9xLJz1 2

Try it online in the Pyth Compiler/Executor: demo | test cases
Idea
Assume all input characters have already been mapped to the integers that step 2 specifies.
For every 3-digit ternary number, we have that xyz3 = 9x + 3y + z, so modular division by 9 yields quotient x and residue 3y + z.
If the input is abc3 def3 ghi3, applying modular division to each yields a, 3b + c, d, 3e + f, g, 3h + i.
After rotating the list from above one unit to the left, we can group the integers into pairs. This yields the list (3b + c, d), (3e + f, g), (3h + i, a).
Now, if we convert (3y + z, w) from base 3 to integer, we obtain 3(3y + z) + w = 9y + 3z + w = zyw3.
Thus, applying base conversion to the list of pairs gives us bcd3 efg3 hia3, which is precisely the result of rotating the concatenated ternary digits one unit to the left.
All that's left to do is mapping the resulting integers back to characters.
Code
J+Gd                        Concatenate "a...z" (G) with " " (d) and save in J.
                    L z     For each character in the input(z):
                   x J        Compute its index in J.
                 R          For each index I:
               .D 9           Compute (I / 9, I % 9).
              s             Concatenate the resulting pairs.
            .<         1    Rotate the resulting list one unit to the left.
           c             2  Split it back into pairs.
         R                  For each pair:
        i 3                   Perform conversion from base 3 to integer.
      L                     For each resulting integer:
     @ J                      Select the element of J at that index.
    s                       Concatenate the resulting characters.

A:

Python 2, 96
s=input()
r=y=''
for c in s+s[0]:x=(ord(c)-97)%91;r+=y and chr((y%9*3+x/9-26)%91+32);y=x
print r

Converts a character c to a value x as x=(ord(c)-97)%91, with the modulo affecting only space to convert it to 26. The reverse conversion is i to chr((i-26)%91+32), with the modulo only affecting i=26 to make it become spaces.
We loop through the characters, noting the current value x and the previous value y. We use the last two ternary digits of y, found as y%9, and the first ternary digit of x, found as x/9. The value of the concatenation is y%9*3+x/9. There's probably some optimizations combining this arithmetic with the shifting by 97 and fixing of space.
We make this loop around, we return to the first character of the string at the end. We also do one preparation loop to write in a previous value y, suppressing the character for the first loop when y has not yet been initialized.

