オフィスアワーがそろそろ始まるよ!()

Cとのコンパイル

ZenとCとが混在するプロジェクトをビルドスクリプトで取り扱うことができます。ここではそのようなプロジェクトのビルドスクリプトを作成します。

Zenの標準ライブラリには暗号化モジュールが含まれています。これをC言語から使うサンプルコードを考えます。

Zen標準ライブラリにあるChaCha20というアルゴリズムで暗号化、復号化します。このアルゴリズムを深く理解する必要はありませんが、サンプルコードの理解のために少しだけ説明します。

ChaCha20の特徴は、同じパラメータを渡すと、暗号化と復号化が同じアルゴリズムでできる、ということです。つまり、平文とパラメータとをアルゴリズムにかけることで暗号文を得られ、その暗号文と暗号化時のパラメータとを再度アルゴリズムにかけることで平文を復元できます。

ChaCha20で暗号化 / 復号化する関数はstd.crypto.chaCha20IETFです。この関数をC言語から呼び出せるように、Zen側にラッパー関数chacha20src/crypto.zenに用意します。処理内容は、C言語から受け取ったポインタを、chaCha20IETFが要求するスライスやZenの配列に変換しているだけです。

examples/ch14-c/mixing/src/crypto.zen:3:18

const chaCha20IETF = std.crypto.chaCha20IETF;

export fn chacha20(out_ptr: [*]u8
                 , in_ptr: [*]const u8
                 , len: usize
                 , counter: u32
                 , key_ptr: [*]u8
                 , nonce_ptr: [*]u8) void {
    const out = out_ptr[0..len];
    const in = in_ptr[0..len];
    const key = @ptrCast(*[32]u8, key_ptr[0..32].ptr);
    const nonce = @ptrCast(*[12]u8, nonce_ptr[0..12].ptr);

    // Zenの標準ライブラリにある暗号化関数
    chaCha20IETF(out, in, counter, key.*, nonce.*);
}

chacha20関数を呼び出すCソースファイルsrc/main.cを用意します。2回関数を呼び出し、平文→暗号文→平文と変換し、最後の平文を標準出力に表示します。

examples/ch14-c/mixing/src/main.c:1:36

#include <stdio.h>
#include <string.h>
// `crypto.zen`のビルドで自動生成されるヘッダ
#include <crypto.h>

int main(void) {
    // 暗号化するテキスト
    char plain_text[] = "Zen encrypts me!";
    // 暗号化の準備
    uintptr_t len = strlen(plain_text);
    uint8_t crypted[len];
    uint8_t key[] = {
        0,  1,  2,  3,  4,  5,  6,  7,
        8,  9,  10, 11, 12, 13, 14, 15,
        16, 17, 18, 19, 20, 21, 22, 23,
        24, 25, 26, 27, 28, 29, 30, 31,
    };
    uint8_t nonce[] = {
        0, 0, 0, 0,
        0, 0, 0, 0x4a,
        0, 0, 0, 0,
    };

    // Zenの`crypt`を呼び出して暗号化
    chacha20(crypted, (uint8_t*)plain_text, len, 1, key, nonce);
    
    // Zenの`crypt`を呼び出して復号化
    uint8_t decrypted[len];
    chacha20(decrypted, crypted, len, 1, key, nonce);

    // 暗号化前と同じ文字列"Zen encrypts me!"が出力される
    fwrite(decrypted, len, 1, stdout);
    printf("\n");

    return 0;
}

これらのZenソースファイルとCソースファイルをビルドするためのビルドスクリプトbuild.zenは次の通りです。

examples/ch14-c/mixing/build.zen:1:13

const Builder = @import("std").build.Builder;

pub fn build(b: *Builder) void {
    // `crypto.zen`のオブジェクトファイルを作成する
    // `crypto.h`が自動生成される
    const obj = b.addObject("crypto", "src/crypto.zen");
    // C言語のソースファイルから実行ファイルをビルドする
    const exe = b.addExecutable("zen_crypto", null);
    exe.addCSourceFile("src/main.c", [_][]const u8{"-std=c11"});
    // `crypto.zen`のオブジェクトファイルをビルド対象に追加する
    exe.addObject(obj);
    exe.linkSystemLibrary("c");
    exe.install();
}

ビルドして、実行します。

$ zen build
$ ./zen-cache/bin/zen_crypto 
Zen encrypts me!

このようにZenのビルドスクリプトには、ZenソースファイルとCソースファイルを同時にビルドするための仕組みが備わっています。

☰ 人の生きた証は永遠に残るよう ☰
Copyright © 2018-2019 connectFree Corporation. All rights reserved.
Zen, the Zen three-circles logo and The Zen Programming Language are trademarks of connectFree corporation in Japan and other countries.