Version 1 of Matrix multiplication and encryption

Updated 2002-06-04 07:38:21

Richard Suchenwirth 2002-06-01 - After function mapping, here is an application for matrix multiplications: encryption. We use map to transpose the second matrix in multiplication, and again to multiply elementwise:

 proc mat* {A B} {
    set C {}
    set Bt [eval map list $B]
    foreach arow $A {
        set crow {}
        foreach bcol $Bt {
            lappend crow [sum [map * $arow $bcol]]
        }
        lappend C $crow
    }
    set C
 }
 proc map {fun args} {
    set cmd "foreach "
    set fargs {}
    for {set i 0} {$i<[llength $args]} {incr i} {
        append cmd "$i [string map [list @ $i] {[lindex $args @]}] "
        lappend fargs $$i
    }
    append cmd [string map [list @f $fun @a [join $fargs]] {{
        lappend res [@f @a]
    }}]
    set res {}
    eval $cmd
    set res
 }
 proc * {a b} {expr {$a*$b}}
 proc sum list {expr [join $list +]}

if 0 {We can do matrix multiplication now - so what? Here's an interesting application in cryptography (from a German math book): given a string to encrypt, e.g.

 This is matrix magic

convert each character to a number (e.g. decimal Unicode); group each four characters into a 2x2 matrix; multiply that with a same-sized encryption matrix; transmit the resulting sequence of matrix contents, which in the example look like

 -20 208 -10 230 -73 210 83 64 12 194 2 228 -15 240 -77 218 -6 206 6 198

Decoding such a cryptogram goes backwards: group the numbers into 2x2 matrixes; multiply with the inverse of the encryption matrix (this is the really secret part); format into the corresponding characters.

This simple encryption has the property that same letters have unequal equivalents, depending on the context - e.g. "i" comes as -10, 210, -15, 6 above; but equal 4-grams of course have the same code:

 % matrixEncrypt foolfool => -9 222 3 216 -9 222 3 216

}

 proc matrixEncrypt {s {M {{1 0} {-1 2}}}} {
    if {[set ls [string length $s]]%4} {
        append s [string repeat " " [expr 4-$ls%4]]
    }
    set res ""
    foreach {a b c d} [map c2i [split $s ""]] {
        eval lappend res [mat* "{$a $b} {$c $d}" $M]
    }
    eval concat $res ;# flatten the list of rows
 }
 proc matrixDecrypt {numbers {M {{1 0} {.5 .5}}}} {
    foreach {a b c d} $numbers {
        eval lappend t [mat* "{$a $b} {$c $d}" $M]
    }
    join [map n2c [eval concat $t]] ""
 }
 #------------ little helper functions for mapping:
 proc c2i c {scan $c %c}
 proc n2c n {format %c [expr round($n)]}

if 0 {We can experiment how cryptic the output gets:

 % matrixEncrypt a
 65 64 0 64
 % matrixEncrypt aa
 0 194 0 64
 % matrixEncrypt aaa
 0 194 65 64
 % matrixEncrypt aaaa
 0 194 0 194
 % matrixEncrypt "Hello, world"
 -29 202 0 216 67 88 -87 238 -3 228 8 200

One might also try larger matrix sizes - but what's always required is that sender and receiver agree on one matrix, and the inverse matrix is used in decoding - just I don't have matrix inversion algorithms handy ;-( }


Category Cryptography | Arts and crafts of Tcl-Tk programming