· 

Rustに触れる

次にくるコンピュータ言語はRustだ。と言われてから数年たったと思う。それはまだ、流行っていない。好奇心でちょっと触ってみることにする。お題はAES128(Rijndael)の実装。まぁ何を隠そう、この題材にするためにわざわざ先日C言語で自力でコードを書いたわけであります。実は。

ではRustをインストールします。Windows環境をよごさないように(Windowsはすぐよごれるんよねー)WSLに入れます。ここの通りやって、すごく簡単にインストールできます。

ところで、WSLがずいぶんフレンドリーになって、コマンドで

wsl --install

ってするだけで、インストールできるようになってます。勝手にUbuntuがインストールされちゃうけど。で、Windows10でも最初からWSLgが有効なので、特に何もすることなくGUIアプリも動きます。すでにWSLをインストールしちゃっている場合も、

wsl --update

で、WSLgが有効なWSLに更新されます。

もう、WSLだけでなんでもやり切れちゃうんじゃないかと思う。(願望)

 

で、Rustのインストール。

hoge@Inspiron:~$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
info: downloading installer
 
Welcome to Rust!
 
This will download and install the official compiler for the Rust
programming language, and its package manager, Cargo.
 
Rustup metadata and toolchains will be installed into the Rustup
home directory, located at:
 
  /home/hoge/.rustup
 
This can be modified with the RUSTUP_HOME environment variable.
 
The Cargo home directory is located at:
 
  /home/hoge/.cargo
 
This can be modified with the CARGO_HOME environment variable.
 
The cargo, rustc, rustup and other commands will be added to
Cargo's bin directory, located at:
 
  /home/hoge/.cargo/bin
 
This path will then be added to your PATH environment variable by
modifying the profile files located at:
 
  /home/hoge/.profile
  /home/hoge/.bashrc
 
You can uninstall at any time with rustup self uninstall and
these changes will be reverted.
 
Current installation options:
 
 
   default host triple: x86_64-unknown-linux-gnu
     default toolchain: stable (default)
               profile: default
  modify PATH variable: yes
 
1) Proceed with installation (default)
2) Customize installation
3) Cancel installation
>1
 
info: profile set to 'default'
info: default host triple is x86_64-unknown-linux-gnu
info: syncing channel updates for 'stable-x86_64-unknown-linux-gnu'
info: latest update on 2023-07-13, rust version 1.71.0 (8ede3aae2 2023-07-12)
info: downloading component 'cargo'
info: downloading component 'clippy'
info: downloading component 'rust-docs'
 13.6 MiB /  13.6 MiB (100 %)  10.1 MiB/s in  1s ETA:  0s
info: downloading component 'rust-std'
 25.4 MiB /  25.4 MiB (100 %)  10.7 MiB/s in  2s ETA:  0s
info: downloading component 'rustc'
 64.0 MiB /  64.0 MiB (100 %)   9.0 MiB/s in 36s ETA:  0s
info: downloading component 'rustfmt'
info: installing component 'cargo'
info: installing component 'clippy'
info: installing component 'rust-docs'
 13.6 MiB /  13.6 MiB (100 %)   6.7 MiB/s in  2s ETA:  0s
info: installing component 'rust-std'
 25.4 MiB /  25.4 MiB (100 %)  16.7 MiB/s in 55s ETA:  0s
info: installing component 'rustc'
 64.0 MiB /  64.0 MiB (100 %)  18.6 MiB/s in 57s ETA:  0s
info: installing component 'rustfmt'
info: default toolchain set to 'stable-x86_64-unknown-linux-gnu'
 
  stable-x86_64-unknown-linux-gnu installed - rustc 1.71.0 (8ede3aae2 2023-07-12)
 
Rust is installed now. Great!

To get started you may need to restart your current shell.
This would reload your PATH environment variable to include
Cargo's bin directory ($HOME/.cargo/bin).
 
To configure your current shell, run:
source "$HOME/.cargo/env"

途中で1を押すだけで、後は勝手にやってくれます。そして、終わったら、

source ~/.cargo/env

しろって言っているのかな、、、まぁ悪影響はないだろうからやっておく。

で、フォルダを潜っていって、cargoコマンドでプロジェクト(ていうのか?)を作り、VSCodeを起動。(いつの間にかDebianからUbuntuに乗り換えてるやんってつっ込まないでー)

Hello Worldが書いてあります。

では、AES128のコードを書こう。

const S:[[u8;16];16]=[
    [0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76],
    [0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0],
    [0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15],
    [0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75],
    [0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84],
    [0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf],
    [0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8],
    [0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2],
    [0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73],
    [0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb],
    [0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79],
    [0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08],
    [0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a],
    [0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e],
    [0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf],
    [0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16] 
];
const INVS:[[u8;16];16]=[
    [0x52,0x09,0x6a,0xd5,0x30,0x36,0xa5,0x38,0xbf,0x40,0xa3,0x9e,0x81,0xf3,0xd7,0xfb],
    [0x7c,0xe3,0x39,0x82,0x9b,0x2f,0xff,0x87,0x34,0x8e,0x43,0x44,0xc4,0xde,0xe9,0xcb],
    [0x54,0x7b,0x94,0x32,0xa6,0xc2,0x23,0x3d,0xee,0x4c,0x95,0x0b,0x42,0xfa,0xc3,0x4e],
    [0x08,0x2e,0xa1,0x66,0x28,0xd9,0x24,0xb2,0x76,0x5b,0xa2,0x49,0x6d,0x8b,0xd1,0x25],
    [0x72,0xf8,0xf6,0x64,0x86,0x68,0x98,0x16,0xd4,0xa4,0x5c,0xcc,0x5d,0x65,0xb6,0x92],
    [0x6c,0x70,0x48,0x50,0xfd,0xed,0xb9,0xda,0x5e,0x15,0x46,0x57,0xa7,0x8d,0x9d,0x84],
    [0x90,0xd8,0xab,0x00,0x8c,0xbc,0xd3,0x0a,0xf7,0xe4,0x58,0x05,0xb8,0xb3,0x45,0x06],
    [0xd0,0x2c,0x1e,0x8f,0xca,0x3f,0x0f,0x02,0xc1,0xaf,0xbd,0x03,0x01,0x13,0x8a,0x6b],
    [0x3a,0x91,0x11,0x41,0x4f,0x67,0xdc,0xea,0x97,0xf2,0xcf,0xce,0xf0,0xb4,0xe6,0x73],
    [0x96,0xac,0x74,0x22,0xe7,0xad,0x35,0x85,0xe2,0xf9,0x37,0xe8,0x1c,0x75,0xdf,0x6e],
    [0x47,0xf1,0x1a,0x71,0x1d,0x29,0xc5,0x89,0x6f,0xb7,0x62,0x0e,0xaa,0x18,0xbe,0x1b],
    [0xfc,0x56,0x3e,0x4b,0xc6,0xd2,0x79,0x20,0x9a,0xdb,0xc0,0xfe,0x78,0xcd,0x5a,0xf4],
    [0x1f,0xdd,0xa8,0x33,0x88,0x07,0xc7,0x31,0xb1,0x12,0x10,0x59,0x27,0x80,0xec,0x5f],
    [0x60,0x51,0x7f,0xa9,0x19,0xb5,0x4a,0x0d,0x2d,0xe5,0x7a,0x9f,0x93,0xc9,0x9c,0xef],
    [0xa0,0xe0,0x3b,0x4d,0xae,0x2a,0xf5,0xb0,0xc8,0xeb,0xbb,0x3c,0x83,0x53,0x99,0x61],
    [0x17,0x2b,0x04,0x7e,0xba,0x77,0xd6,0x26,0xe1,0x69,0x14,0x63,0x55,0x21,0x0c,0x7d]
];
static mut W:[[u8;16];11]=[[0;16];11];
const RCON:[u8;10]=[0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x1b,0x36];

fn subword(indata:&mut [u8]){
    for i in 0..16{
        indata[i]=S[((indata[i]>>4)&0x0F) as usize][((indata[i]>>0)&0x0F) as usize];
    }
}
fn rotword(indata:&mut [u8]){
    let tmp:u8=indata[0];
    indata[0]=indata[1];
    indata[1]=indata[2];
    indata[2]=indata[3];
    indata[3]=tmp;
}
fn keyexpansion_single(num:u8){
    unsafe{
        for i in 0..4{
            W[num as usize][i]=W[(num-1) as usize][12+i];
        }
        rotword(&mut W[num as usize][0..4]);
        subword(&mut W[num as usize][0..16]);
        W[num as usize][0]^=RCON[(num-1) as usize];
        for i in 0..4{
            W[num as usize][i]^=W[(num-1) as usize][i];
            W[num as usize][i+4]=W[num as usize][i]^W[(num-1) as usize][i+4];
            W[num as usize][i+8]=W[num as usize][i+4]^W[(num-1) as usize][i+8];
            W[num as usize][i+12]=W[num as usize][i+8]^W[(num-1) as usize][i+12];
        }
    }
}
fn keyexpansion(key:&[u8]){
    for i in 0..16{
        unsafe{
            W[0][i]=key[i];
        }
    }
    for i in 1..11{
        keyexpansion_single(i);
    }
}
fn addroundkey(src:&mut [u8],nround:u8){
    for i in 0..16{
        unsafe{
            src[i]^=W[nround as usize][i];
        }
    }
}
fn subbytes(src:&mut [u8]){
    for i in 0..16{
        src[i]=S[((src[i]>>4)&0x0F) as usize][((src[i]>>0)&0x0F) as usize];
    }
}
fn invsubbytes(src:&mut [u8]){
    for i in 0..16{
        src[i]=INVS[((src[i]>>4)&0x0F) as usize][((src[i]>>0)&0x0F) as usize];
    }
}
fn shiftrows(src:&mut [u8]){
    let mut temp:[u8;8]=[0;8];
    for i in 0..4{
        for j in 0..4{
            temp[j]=src[j*4+i];
            temp[j+4]=src[j*4+i];
        }
        for j in 0..4{
            src[j*4+i]=temp[j+i];
        }
    }
}
fn invshiftrows(src:&mut [u8]){
    let mut temp:[u8;8]=[0;8];
    for i in 0..4{
        for j in 0..4{
            temp[j]=src[j*4+i];
            temp[j+4]=src[j*4+i];
        }
        for j in 0..4{
            src[j*4+i]=temp[j+4-i];
        }
    }
}
fn mul(a:u8,b:u8)->u8{
    let mut x:u8=0;
    let isrc:[u8;4]=[8,4,2,1];
    for i in isrc.iter(){
        if (x&0x80)>0 {
            x<<=1;
            x^=0x1b;
        }else{
            x<<=1;
        }
        if (b&i)>0 {
            x^=a;
        }
    }
    return x;
}
fn mixcolumn_single(r:&mut [u8]){
    let mut t:[u8;4]=[0;4];
    for i in 0..4{
        t[i]=r[i];
    }
    r[0]=mul(t[0],2)^mul(t[1],3)^mul(t[2],1)^mul(t[3],1);
    r[1]=mul(t[1],2)^mul(t[2],3)^mul(t[3],1)^mul(t[0],1);
    r[2]=mul(t[2],2)^mul(t[3],3)^mul(t[0],1)^mul(t[1],1);
    r[3]=mul(t[3],2)^mul(t[0],3)^mul(t[1],1)^mul(t[2],1);
}
fn mixcolumns(src:&mut [u8]){
    for i in 0..4{
        mixcolumn_single(&mut src[(i*4)..(i*4+4)]);
    }
}
fn invmixcolumn_single(r:&mut [u8]){
    let mut t:[u8;4]=[0;4];
    for i in 0..4{
        t[i]=r[i];
    }
    r[0]=mul(t[0],14)^mul(t[1],11)^mul(t[2],13)^mul(t[3],9);
    r[1]=mul(t[1],14)^mul(t[2],11)^mul(t[3],13)^mul(t[0],9);
    r[2]=mul(t[2],14)^mul(t[3],11)^mul(t[0],13)^mul(t[1],9);
    r[3]=mul(t[3],14)^mul(t[0],11)^mul(t[1],13)^mul(t[2],9);
}
fn invmixcolumns(src:&mut [u8]){
    for i in 0..4{
        invmixcolumn_single(&mut src[(i*4)..(i*4+4)]);
    }
}
fn cipher(data:&mut [u8]){
    addroundkey(data,0);
    for i in 1..10{
        subbytes(data);
        shiftrows(data);
        mixcolumns(data);
        addroundkey(data,i);
    }
    subbytes(data);
    shiftrows(data);
    addroundkey(data,10);
}
fn invcipher(data:&mut [u8]){
    addroundkey(data,10);
    for i in 1..10{
        invshiftrows(data);
        invsubbytes(data);
        addroundkey(data,10-i);
        invmixcolumns(data);
    }
    invshiftrows(data);
    invsubbytes(data);
    addroundkey(data,0);
}

fn main() {
    let key:[u8;16]=[0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f];
    let mut data:[u8;16]=[0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff];
    print!("KEY     :");
    for i in 0..16{
        print!("{:02X}",key[i]);
    }
    println!("");
    print!("PLAIN   :");
    for i in 0..16{
        print!("{:02X}",data[i]);
    }
    println!("");
    keyexpansion(&key);
    cipher(&mut data);
    print!("CHIPHRED:");
    for i in 0..16{
        print!("{:02X}",data[i]);
    }
    println!("");
    invcipher(&mut data);
    print!("PLAIN   :");
    for i in 0..16{
        print!("{:02X}",data[i]);
    }
    println!("");
}

いきなりですが、こうなります。まぁ新しい言語と向き合うのはしんどい。そして、あんまり人間にやさしい言語ではない気がする。C++もそういう感じだけど、愚直に書くのが難しいというか、情報がないというか、、、

苦労した点:

・2次元配列(webにあまり例がなかっただけだけど)

 ・グローバル変数(unsafe乱発してムリやり解決)

・配列の参照渡し

・配列の先頭を変えて参照渡し(スライスっていう)

C言語の当たり前がなかなか難しい。変数って変数なはずなのに変更できない言語仕様って、、、狂気。まぁmutつけて示せってことなんだろうけど。C言語では逆に定数にはconstつけるってのと発想が逆。

 

では、

cargo build

cargo run

する。

できた。

あっさりできたように見えるが、4時間くらいかかったかな、、、

webに親切なexampleやdocumentがかなりあるんだけど、何しろ仕様がストイックすぎ。一方、変数の型を文脈から自動的に決める需要がなさそうな柔軟な機能があるとか、、、なんなんや。CやC++もたまにコードをパッと見て何やっているのかわからないことがあるけど、webにあるRustのコード、まじ呪文。他にもいろいろ壁があるらしく、こちらにまとめてくれている人がいる。

とはいえ、規模の大きいプログラムを書く場合はきっと安心感がある言語なんだろう。コンパイルエラーのコメントも好感が持てるし。今後はできるだけRustを使ってみようと思う。

 

ビ。○○ー○ーの経営の原点12カ条が京○○の経営12カ条と全くおんなじなんやけど、、、方や犯罪。方や神様。