Bacon cipher

From Rosetta Code
Revision as of 20:54, 11 September 2015 by rosettacode>Craigd (→‎{{header|REXX}}: Added zkl)
Bacon cipher is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

Bacon's cipher is a method of steganography created by Francis Bacon. This task is to implement a program for encryption and decryption of plaintext using the simple alphabet of the Baconian cipher or some other kind of representation of this alphabet (make anything signify anything).

The Baconian alphabet:

a   AAAAA   g     AABBA   n    ABBAA   t     BAABA
b   AAAAB   h     AABBB   o    ABBAB   u-v   BAABB
c   AAABA   i-j   ABAAA   p    ABBBA   w     BABAA
d   AAABB   k     ABAAB   q    ABBBB   x     BABAB
e   AABAA   l     ABABA   r    BAAAA   y     BABBA
f   AABAB   m     ABABB   s    BAAAB   z     BABBB

C++

Bacon cipher implementation

<lang cpp>

  1. include <iostream>
  2. include <algorithm>
  3. include <vector>
  4. include <bitset>
  5. include <string>

class bacon { public:

   bacon() {
       int x = 0;
       for( ; x < 9; x++ )
           bAlphabet.push_back( std::bitset<5>( x ).to_string() );
       bAlphabet.push_back( bAlphabet.back() );
       
       for( ; x < 20; x++ )
           bAlphabet.push_back( std::bitset<5>( x ).to_string() );
       bAlphabet.push_back( bAlphabet.back() );
       
       for( ; x < 24; x++ )
           bAlphabet.push_back( std::bitset<5>( x ).to_string() );
   }
   std::string encode( std::string txt ) {
       std::string r;
       size_t z;
       for( std::string::iterator i = txt.begin(); i != txt.end(); i++ ) {
           z = toupper( *i );
           if( z < 'A' || z > 'Z' ) continue;
           r.append( bAlphabet.at( ( *i & 31 ) - 1 ) );
       }
       return r;
   }
   std::string decode( std::string txt ) {
       size_t len = txt.length();
       while( len % 5 != 0 ) len--;
       if( len != txt.length() ) txt = txt.substr( 0, len );
       std::string r;
       for( size_t i = 0; i < len; i += 5 ) {
           r.append( 1, 'A' + std::distance( bAlphabet.begin(), std::find( bAlphabet.begin(), bAlphabet.end(), txt.substr( i, 5 ) ) ) );
       }
       return r;
   }

private:

   std::vector<std::string> bAlphabet;

}; </lang>

These next 2 classes use the 0's & 1's generated by the 'Bacon encryption' to create different the outputs. One could go wild here... <lang cpp> class cipherI { public:

   std::string encode( std::string txt ) {
       txt = b.encode( txt );
       std::string e, d = "one morning, when gregor samsa woke from troubled dreams, he found himself transformed "
       "in his bed into a horrible vermin. he lay on his armour-like back, and if he lifted his head a little he "
       "could see his brown belly, slightly domed and divided by arches into stiff sections.";
       size_t r = 0; 
       char t;
       for( std::string::iterator i = txt.begin(); i != txt.end(); i++ ) {
           t = d.at( r );
           while( t < 'a' || t > 'z' ) {
               e.append( 1, t );
               r++;
               t = d.at( r );
           }
           r++;
           e.append( 1, *i == '1' ? t - 32 : t );
       }
       return e;
   }
   std::string decode( std::string txt ) {
       std::string h;
       for( std::string::iterator i = txt.begin(); i != txt.end(); i++ ) {
           if( *i < 'a' && ( *i < 'A' || *i > 'Z' ) || *i > 'z' ) continue;
           h.append( 1, *i & 32 ? '0' : '1' );
       }
       return b.decode( h );
   }

private:

   bacon b;

};

class cipherII { public:

   std::string encode( std::string txt ) {
       txt = b.encode( txt );
       std::string e;
       for( std::string::iterator i = txt.begin(); i != txt.end(); i++ )
           e.append( 1, *i == '0' ? 0xf9 : 0xfa );
       return e;
   }
   std::string decode( std::string txt ) {
       std::string h;
       for( std::string::iterator i = txt.begin(); i != txt.end(); i++ ) {
           h.append( 1, *i == ( char )0xf9 ? '0' : '1' );
       }
       return b.decode( h );
   }

private:

   bacon b;

};

int main( int argc, char* argv[] ) {

   cipherI c1;
   cipherII c2;
   std::string s = "lets have some fun with bacon cipher";
   std::string h1 = c1.encode( s ),
               h2 = c2.encode( s );
   std::cout << h1 << std::endl << std::endl << c1.decode( h1 ) << std::endl << std::endl;
   std::cout << h2 << std::endl << std::endl << c2.decode( h2 ) << std::endl << std::endl;
   return 0;

} </lang>

Output:
oNe MornIng, WheN gRegoR saMSA woke fRom TRouBleD dreAmS, He FoUnD HimSelf tRaNS
foRMeD In hIs Bed iNto a HorRiblE VErmin. He lay on hiS arMOuR-lIKe back, And If
 he lIFTed hIS HeaD a lIttle

LETSHAUESOMEFUNWITHBACONCIPHER

¨·¨·¨¨¨·¨¨·¨¨·¨·¨¨¨·¨¨···¨¨¨¨¨·¨¨··¨¨·¨¨·¨¨¨·¨··¨·¨·¨··¨¨·¨¨¨¨·¨··¨¨··¨··¨¨·¨·¨¨
¨·¨¨¨·¨¨·¨¨¨···¨¨¨¨·¨¨¨¨¨¨¨¨·¨¨··¨·¨··¨¨¨¨¨·¨¨·¨¨¨¨···¨¨¨···¨¨·¨¨·¨¨¨¨

LETSHAUESOMEFUNWITHBACONCIPHER

J

Implementation:

<lang J>alfa=: 'ABCDEFGHIKLMNOPQRSTUWXYZ' beta=: 26{.(}.~i.&'A')a. norm=: ([ -. -.)&alfa@(rplc&('JIVU'))@toupper enca=:(5#2),@:#:alfa i. norm gena=: ]`((,:tolower)@(beta {~ 26 ?@#~ #))}

encrypt=: gena@enca@norm decrypt=: alfa {~ _5 #.\ 90 < a.&i.</lang>

We use random letters as the basis for our steganography and we use case to represent "font".

Example use:

<lang J> encrypt 'this is a test' nWVkJAPkamEuUJIeTGKnUsTVRfAWWuNBIIHdEIcOAPuTBeXKQduQAdU

  encrypt 'this is a test'

sFLkBQKqqaQsGGXzAXQsKlZFBcILRlUIRAQaEQoNUBcHIhFTWbeRAlM

  decrypt encrypt 'this is a test'

THISISATEST</lang>

Python

This deviates from the Bacon method as it encodes to different capitalisation of text rather than differences in font.

<lang python>import string

sometext = """All children, except one, grow up. They soon know that they will grow up, and the way Wendy knew was this. One day when she was two years old she was playing in a garden, and she plucked another flower and ran with it to her mother. I suppose she must have looked rather delightful, for Mrs. Darling put her hand to her heart and cried, "Oh, why can't you remain like this for ever!" This was all that passed between them on the subject, but henceforth Wendy knew that she must grow up. You always know after you are two. Two is the beginning of the end.

Of course they lived at 14 [their house number on their street], and until Wendy came her mother was the chief one. She was a lovely lady, with a romantic mind and such a sweet mocking mouth. Her romantic mind was like the tiny boxes, one within the other, that come from the puzzling East, however many you discover there is always one more; and her sweet mocking mouth had one kiss on it that Wendy could never get, though there it was, perfectly conspicuous in the right-hand corner.""".lower()

lc2bin = {ch: '{:05b}'.format(i)

         for i, ch in enumerate(string.ascii_lowercase + ' .')}

bin2lc = {val: key for key, val in lc2bin.items()}

phrase = 'Rosetta code Bacon cipher example secret phrase to encode in the capitalisation of peter pan'.lower()

def to_5binary(msg):

   return ( ch == '1' for ch in .join(lc2bin.get(ch, ) for ch in msg.lower()))

def encrypt(message, text):

   bin5 = to_5binary(message)
   textlist = list(text.lower())
   out = []
   for capitalise in bin5:
       while textlist:
           ch = textlist.pop(0)
           if ch.isalpha():
               if capitalise:
                   ch = ch.upper()
               out.append(ch)
               break
           else:
               out.append(ch)
       else:
           raise Exception('ERROR: Ran out of characters in sometext')
   return .join(out) + '...'


def decrypt(bacontext):

   binary = []
   bin5 = []
   out = []
   for ch in bacontext:
       if ch.isalpha():
           binary.append('1' if ch.isupper() else '0')
           if len(binary) == 5:
               bin5 = .join(binary)
               out.append(bin2lc[bin5])
               binary = []
   return .join(out)
               

print('PLAINTEXT = \n%s\n' % phrase) encrypted = encrypt(phrase, sometext) print('ENCRYPTED = \n%s\n' % encrypted) decrypted = decrypt(encrypted) print('DECRYPTED = \n%s\n' % decrypted) assert phrase == decrypted, 'Round-tripping error'</lang>

Output:
PLAINTEXT = 
rosetta code bacon cipher example secret phrase to encode in the capitalisation of peter pan

ENCRYPTED = 
All cHiLDReN, exCept One, GroW UP. thEY soon kNOw That tHey WILl groW
Up, aNd tHE wAy wendY knew was tHis. ONE daY WhEN ShE was tWo yEars oLD
SHe wAS PlaYinG in a GARdEn, anD shE pLUCked anoTHer fLOWEr AnD Ran WitH
It To Her MothEr. i supPoSe shE muSt hAve LOOKeD raTHER deLIGHtfuL, for
mrS. daRlinG puT HeR hAnd TO hER HeARt And cRied, "OH, wHy caN't yOU
RemaiN LikE thIS fOr eVer!" thIS wAS AlL tHat PAssED BetWeeN ThEm on
tHe subjecT, BUT hEnceForTH wendy kNeW ThAt shE muSt grow uP. yoU AlWays
kNOW afTEr YOU aRe tWO. Two iS tHE BeGinNING of The End.

OF coUrsE theY LIvEd aT 14 [THEir housE NuM...

DECRYPTED = 
rosetta code bacon cipher example secret phrase to encode in the capitalisation of peter pan

<lang racket>#lang racket (require xml)

(define (char->bacon-number C)

 (define c (char-downcase C))
 (define c-code (- (char->integer c) (char->integer #\a)))
 (and (<= 0 c-code 26) (- c-code (if (> c-code  8) 1 0) (if (> c-code 20) 1 0))))

(define (inr-encode bacons f-cs seg/r rv/r last-bacon-bit fce)

 (cond
   [(null? bacons) (append (reverse (if (null? seg/r) rv/r (cons seg/r rv/r))) (list f-cs))]    
   [(null? f-cs) (error 'bacon-encode->list "not enough false message to hide the text")]    
   [(zero? last-bacon-bit) (inr-encode (cdr bacons) f-cs seg/r rv/r 5 fce)]    
   [(not (char-alphabetic? (car f-cs)))
    (inr-encode bacons (cdr f-cs) (cons (car f-cs) seg/r) rv/r last-bacon-bit fce)]    
   [else
    (define bit (sub1 last-bacon-bit))
    (define bs? (bitwise-bit-set? (car bacons) bit))
    (match-define (cons f-a f-d) f-cs)
    (match (cons bs? fce)
      [(or '(#f . 1) '(#t . 2)) (inr-encode bacons f-d (cons f-a seg/r) rv/r bit fce)]
      [_ (inr-encode bacons f-d (list f-a) (cons (reverse seg/r) rv/r) bit (if bs? 2 1))])]))

(define (bacon-encode->segments-list plain-text false-message)

 (define bacon-numbers (filter-map char->bacon-number (string->list plain-text)))
 (map list->string (inr-encode bacon-numbers (string->list false-message) null null 5 1)))

(define (bacon-encode->html plain-text false-message

                           (->face1 (λ (s) `(span ((face "1")) ,s)))
                           (->face2 (λ (s) `(span ((face "2")) ,s))))
 (define segments (bacon-encode->segments-list plain-text false-message))
 (xexpr->string
  (list* 'div '((style "white-space: pre"))
         (for/list ((seg (in-list segments)) (face (in-cycle (in-list (list ->face1 ->face2)))))
           (face seg)))))

(module+ main

 (define plain-text "i wrote this F.B.")
 (define false-text #<<EOS

To be, or not to be, that is the question: Whether 'tis Nobler in the mind to suffer The Slings and Arrows of outrageous Fortune, [...] EOS

   )
 
 (displayln (bacon-encode->html plain-text false-text values (λ (s) `(i ,s)))))</lang>
Output:
  • Literal
<div style="white-space: pre">T<i>o </i>be, o<i>r </i>n<i>o</i>t t<i>o </i>be, tha<i>t i</i>s <i>th</i>e q<i>u</i>est<i>i</i>on:
<i>W</i>he<i>t</i>her '<i>tis </i>N<i>o</i>ble<i>r </i>in t<i>h</i>e m<i>i</i>n<i>d </i>to su<i>f</i>fer
The Slings and Arrows of outrageous Fortune,
[...]</div>
  • HTML
To be, or not to be, that is the question:

Whether 'tis Nobler in the mind to suffer The Slings and Arrows of outrageous Fortune,

[...]

REXX

assigned cipher codes

This REXX version supports a full (26-letter) Roman (Latin) alphabet, plus a few punctuation symbols:
      .   (period),     ,   (comma),     ?   (question mark),     :   (colon),     !   (exclamation mark),   and blanks.

All alphabetic letters are handled as if they were in uppercase   (i.e., lowercase letters are uppercased). <lang rexx>/*REXX program implements and demonstrates a (full) "Bacon" cipher (cypher).*/ parse arg plain /*obtain optional arguments from the CL*/ if plain= then plain = "The quick brown fox jumped over the lazy dog."

                                      /* [↓]  code supports complete alphabet*/

@.=; @.a=11111; @.b=11110; @.c=11101; @.d=11100; @.e=11011; @.f=11010; @.g=11001

    @.h=11000; @.i=10111; @.j=00111; @.k=10110; @.l=10101; @.m=10100; @.n=10011
    @.o=10010; @.p=10001; @.q=10000; @.r=01111; @.s=01110; @.t=01101; @.u=01100
    @.v=00100; @.w=01011; @.x=01010; @.y=01001; @.z=01000; @.?=00000; @.!=00101
    @..=00110;   _=','  ; @._=00001;   _=' '  ; @._=00011;   _=':'  ; @._=00010
                                      /* [↑]  code supports some punctuation.*/

say ' plain text: ' plain /*display the original (plain) text. */

     encoded=BaconEnc(plain)          /*encode using a (full)  Bacon  cipher.*/

say 'cipher text: ' encoded /*display the ciphered (coded) text. */

     decoded=BaconDec(encoded)        /*decode ciphered text──►plain (almost)*/

say 'cycled text: ' decoded /*display the recycled text (~ plain),*/ exit /*stick a fork in it, we're all done. */ /*────────────────────────────────────────────────────────────────────────────*/ BaconEnc: procedure expose @.; arg x; $=; Lx=length(x)

           do j=1  for Lx;           _=substr(x,j,1);      $=$ || @._;      end
         return $

/*────────────────────────────────────────────────────────────────────────────*/ BaconDec: procedure expose @.; parse arg x; $=; Lx=length(x)

           do k=0 for 256; _=d2c(k); if @._== then iterate; q=@._; !.q=_; end
           do j=1  to Lx  by 5;      y=substr(x,j,5);      $=$ || !.y;      end
         return $</lang>

output   when using the default input:

 plain text:  The quick brown fox jumped over the lazy dog.
cipher text:  011011100011011000111000001100101111110110110000111111001111100100101110011000111101010010010100001100111011001010010001110111110000011100100010011011011110001101101110001101100011101011111101000010010001111100100101100100110
cycled text:  THE QUICK BROWN FOX JUMPED OVER THE LAZY DOG.

generated cipher codes

The twp glyphs (characters) chosen for this REXX program are:

  •   the   bottom tee       (sometimes known as the   bottom junction)
  •   the     top tee           (sometimes known as the   top junction)

<lang rexx>/*REXX program implements and demonstrates a (full) "Bacon" cipher (cypher).*/ parse arg plain /*obtain optional arguments from the CL*/ if plain= then plain = "The quick brown fox jumped over the lazy dog."

                                      /*alphabet must be in uppercase letters*/

alphabet= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ .,?!:' /*list of letters & punctuation.*/ @.= /*assign a default for all chars*/

    do j=0  for min(32,length(alphabet));              _=substr(alphabet,j+1,1)
    @._=translate(right(x2b(d2x(j)), 5, 0),  '┴┬', 01)
    end   /*j*/                       /* [↑]  build the symbol table (max=32)*/
                                      /* [↑]  code supports some punctuation.*/

say ' plain text: ' plain /*display the original (plain) text. */

     encoded=BaconEnc(plain)          /*encode using a (full)  Bacon  cipher.*/

say 'cipher text: ' encoded /*display the ciphered (coded) text. */

     decoded=BaconDec(encoded)        /*decode ciphered text──►plain (almost)*/

say 'cycled text: ' decoded /*display the recycled text (~ plain),*/ exit /*stick a fork in it, we're all done. */ /*────────────────────────────────────────────────────────────────────────────*/ BaconEnc: procedure expose @.; arg x; $=; Lx=length(x)

           do j=1  for Lx;           _=substr(x,j,1);      $=$ || @._;      end
         return $

/*────────────────────────────────────────────────────────────────────────────*/ BaconDec: procedure expose @.; parse arg x; $=; Lx=length(x)

           do k=0 for 256; _=d2c(k); if @._== then iterate; q=@._; !.q=_; end
           do j=1  to Lx  by 5;      y=substr(x,j,5);      $=$ || !.y;      end
         return $</lang>

output   when using the default input:

 plain text:  The quick brown fox jumped over the lazy dog.
cipher text:  ┬┴┴┬┬┴┴┬┬┬┴┴┬┴┴┬┬┴┬┴┬┴┴┴┴┬┴┬┴┴┴┬┴┴┴┴┴┴┬┴┴┬┴┬┴┬┬┴┬┴┴┴┴┴┬┬┴┴┴┬┴┬┬┬┴┬┴┬┬┴┴┬┬┴┬┬┬┴┬┴┴┴┬┴┬┴┬┬┬┴┬┴┬┬┬┬┬┴┬┴┴┬┴┴┬┬┴┬┴┴┴┬┬┴┴┴┬┬┬┬┴┴┬┴┴┴┴┴┬┬┬┬┴┬┴┴┬┬┬┴┬┴┬┴┬┴┴┬┴┴┬┴┴┴┬┬┬┴┬┴┬┴┴┬┬┴┴┬┬┬┴┴┬┴┴┬┬┴┬┴┴┬┴┬┬┴┴┴┴┴┬┬┴┴┬┬┬┴┴┴┬┬┴┬┴┴┴┴┬┬┴┬┬┬┴┴┴┬┬┴┬┬┴┬┬
cycled text:  THE QUICK BROWN FOX JUMPED OVER THE LAZY DOG.

zkl

Translation of: Python

<lang zkl>class Bacon{

 fcn init(_keyText){
     var [const] keyText=_keyText.toLower(),
       lowerLetters=Utils.Helpers.lowerLetters,

upperLetters=Utils.Helpers.upperLetters, letters=String(lowerLetters,upperLetters), lc2bin=[0..].zip(lowerLetters + " .") //-->("a":"00000", ...) .pump(Dictionary(),fcn([(n,ch)]){ T(ch,"%05.2B".fmt(n)) }), bin2lc=lc2bin.pump(Dictionary(),"copy",T("swap",0,1)); //-->("00000":"a", ...),

     ;
  }
  fcn to5binary(msg){ //-->stream of 1s and 0s
     msg.toLower().pump(String,lc2bin.get.fp1(""))
     .pump(Data,"toAsc",'-(0x30)).howza(0)
  }
  fcn encrypt(msg){ msg=msg.toLower();
     out,bin5:=Sink(String), to5binary(msg);  // capitalization overlay
     keyText:=self.keyText.walker();  // keyText as char stream
     foreach capitalise in (bin5){

while(keyText){ ch:=keyText.next(); if(lowerLetters.holds(ch)){ out.write(capitalise and ch.toUpper() or ch); break; } out.write(ch); } fallthrough{ throw(Exception.ValueError("ERROR: Ran out of characters in key text")) }

     }
     out.write("...").close()  // pad
  }
  fcn decrypt(bacontext){
     bacontext.filter(letters.holds).pump(String,T(Void.Read,4),
       fcn{ vm.arglist.pump(String,upperLetters.holds,"toInt") : bin2lc[_] });
  } 

}</lang> <lang zkl>bacon:=Bacon(

  1. <<<

0'|All children, except one, grow up. They soon know that they will grow up, and the way Wendy knew was this. One day when she was two years old she was playing in a garden, and she plucked another flower and ran with it to her mother. I suppose she must have looked rather delightful, for Mrs. Darling put her hand to her heart and cried, "Oh, why can't you remain like this for ever!" This was all that passed between them on the subject, but henceforth Wendy knew that she must grow up. You always know after you are two. Two is the beginning of the end.

Of course they lived at 14 [their house number on their street], and until Wendy came her mother was the chief one. She was a lovely lady, with a romantic mind and such a sweet mocking mouth. Her romantic mind was like the tiny boxes, one within the other, that come from the puzzling East, however many you discover there is always one more; and her sweet mocking mouth had one kiss on it that Wendy could never get, though there it was, perfectly conspicuous in the right-hand corner.| );

  1. <<<

phrase:="Rosetta code Bacon cipher example secret phrase to encode in the capitalization of peter pan";

println("PLAINTEXT = \n%s".fmt(phrase)); encrypted:=bacon.encrypt(phrase); println("ENCRYPTED = \n%s".fmt(encrypted)); decrypted:=bacon.decrypt(encrypted); println("DECRYPTED = \n%s".fmt(decrypted)); if(phrase.toLower()!=decrypted) throw(Exception.AssertionError("Round-tripping error"));</lang>

Output:
PLAINTEXT = 
Rosetta code Bacon cipher example secret phrase to encode in the capitalization of peter pan
ENCRYPTED = 
All cHiLDReN, exCept One, GroW UP. thEY soon kNOw That tHey WILl groW
Up, aNd tHE wAy wendY knew was tHis. ONE daY WhEN ShE was tWo yEars oLD
SHe wAS PlaYinG in a GARdEn, anD shE pLUCked anoTHer fLOWEr AnD Ran WitH
It To Her MothEr. i supPoSe shE muSt hAve LOOKeD raTHER deLIGHtfuL, for
mrS. daRlinG puT HeR hAnd TO hER HeARt And cRied, "OH, wHy caN't yOU
RemaiN LikE thIS fOr eVer!" thIS wAS AlL tHat PAssED BetWeeN ThEm on
tHe subjecT, BUT hEnceForTH wendy kNeW ThAt shE MusT grow uP. yoU AlWays
kNOW afTEr YOU aRe tWO. Two iS tHE BeGinNING of The End.
 
OF coUrsE theY LIvEd aT 14 [THEir housE NuM...
DECRYPTED = 
rosetta code bacon cipher example secret phrase to encode in the capitalization of peter pan