ブロック暗号の主なモード(ECB, CBC, CFB, OFB, CTR)

ECBモード: Electronic CodeBook mode(電子符号表モード)
CBCモード: Cipher Block Chaining mode(暗号ブロック連鎖モード)
CFBモード: Cipher-FeedBack mode(暗号フィードバックモード)
OFBモード: Output-FeedBack mode(出力フィードバックモード)
CTRモード: CounTeR mode (カウンタモード)

### ECBモード
平文ブロックを暗号化したものが、そのまま暗号文ブロックになる
最後の平文ブロックがブロック長に満たない場合にはパディングと呼ばれるデータを埋める
=> たくさんあるモードの中で最もシンプルだが最も機密性の低いモード
平文の中に同じ値を持つ平文ブロックが複数存在した場合、全て同じ値の暗号文ブロックに変換されてしまう。暗号文を見るだけで平文の繰り返しがわかってしまう

### CBCモード
CBCモードは1つ前の暗号文ブロックと平文ブロックのXORをとり、そのXORの値を暗号化を行う。CBCモードも最後の平文ブロックがブロック長に満たない場合にはパディングを行う
SSL/TLSではCBCモードが使われている
最初の平文ブロックを暗号化する際に、「1つ前の暗号文ブロック」は存在しないので、「1つ前の暗号ブロック」の代わりのビット列を1ブロック分用意する必要がある。このビット列をIV(initial vector)

### CFBモード
CFBモードは1つ前の暗号文ブロックを暗号アルゴリズムの入力に戻す
フィードバックとは、入力へ戻すということを意味する
CFBモードで暗号化して得られる値を鍵ストリームという
ECBやCBCモードでは暗号化アルゴリズムによって直接暗号化されるが、CFBは直接暗号化されるわけではない

### OFBモード
暗号アルゴリズムの出力を暗号アルゴリズムの入力へフィードバック
“1つ前の暗号ブロックを暗号アルゴリズムで暗号化した値”と”平文ブロック”のXOR=暗号文ブロックとなる
OFBでもCBC, CFBと同様にIVを使用する
平文ブロックと暗号アルゴリズムの出力とXORして暗号文ブロックを作っている CFBモードに似ている
OFBモードでは、平文ブロックとは無関係に暗号アルゴリズムを前もってぐるぐる回し、XORするためのビット列をしておく

### CTRモード
1ずつ増加していくカウンタを暗号化して鍵ストレーむを作り出すストリーム暗号
“カウンタを暗号化した値”と”平文ブロック”のXOR=暗号文ブロックとなる
カウンタの初期値は暗号化のたびに異なる値(ノンス)を元にして作る

RSA暗号

function rsa_key_generate (
  $p,
  $q
){
  if ($p == $q) {
    return false;
  }

  $n = (string)gmp_mul($p, $q); //mul-> 乗算
  $n_ gmp_mul(gmp_sub($p, '1'), gmp_sub($q, '1')); // 減算(p-1)(q-1)
  $rand = gmp_random_range(0, gmp_sub($n_, '1')); // random_range -> ランダムな数 0 ~ (n')

  while(true) {
    $coprime_numbers = (string)gmp_gcd($rand, $_n); // gcd -> 最大公約数を返す

    // 最大公約数が1なら互いに素な数
    if($coprime_numbers === '1') {
      $e = (string)$rand;
      break;
    }
    // 非互に素な数減算し再計算
    $rand = gmp_sub($rand, '1');
  }

  $d = (string)gmp_invert($e, $n_); // n'を法としたeの逆数

  // 秘密鍵:d 公開鍵:n, e
  return [$d, $n, $e];
}

function rsa_encryption (
  $a, //暗号化対象の平文
  $n, //公開鍵1
  $e //公開鍵2
){
  $b = [];
  foreach ($a as $value) {
    // aの一つを2乗
    $a_e = gmp_pow($value, $e);
    // e乗した値をnで割った余りを格納
    $b[] = (string)gmp_div_r($a_e, $n);
  }
  return $b;
}

function composite (
  $b, // 暗号文
  $d, // 秘密鍵
  $n // 公開鍵
){
    $a = [];
    foreach ($b as $value) {
      // bの一つをd乗する
      $b_d = gmp_pow($value, $d); // 
      // d乗した値をnで割った余りを格納
      $a[] = (string)gmp_div_r($b_d, $n);
    }
    return $a;
  }
  return $b;
}

// 平文を数値配列に変換
function convert_string_to_integer(
  $str
){
  // 初期配列
  $ord_array = [];

  for ($i = 0; $i < mb_strlen($str); $i ++) {
    $value = mb_substr($str, $i, 1);
    $ord_array[] = mb_ord($value);
  }
  return $ord_array;
}

// 数値配列を文字列に変換
function convert_integer_to_string (
  $int_array
) {
  // 初期文字列
  $chr = '';
  // 配列の数値を全て文字列に変換
  foreach ($int_array as $value){
    // 数値を文字列に
    $chr .= mb_char($value);
  }
  return $chr;
}

【ChatGPT】PHPでリクエストを送ってみる

$input_json = file_get_contents('php://input');
$post = json_decode( $input_json, true );
$req_question = $post['prompt'];

$result = array();

// APIキー
$apiKey = '***';

//openAI APIエンドポイント
$endpoint = 'https://api.openai.com/v1/chat/completions';

$headers = array(
  'Content-Type: application/json',
  'Authorization: Bearer ' . $apiKey
);

// リクエストのペイロード
$data = array(
  'model' => 'gpt-3.5-turbo',
  'messages' => [
    [
    "role" => "system",
    "content" => "新宿はどんな所ですか?"
    ],
    // [
    // "role" => "user",
    // "content" => $req_question
    // ]
  ]
);

// cURLリクエストを初期化
$ch = curl_init();

// cURLオプションを設定
curl_setopt($ch, CURLOPT_URL, $endpoint);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

// APIにリクエストを送信
$response = curl_exec($ch);

// cURLリクエストを閉じる
curl_close($ch);

// 応答を解析
$result = json_decode($response, true);

// 生成されたテキストを取得
$text = $result['choices'][0]['message']['content'];

var_dump($result);

レスポンスは返ってくるが、時間がかかりますね。
$ php index.php
array(6) {
[“id”]=>
string(38) “chatcmpl-7jHpzpu5LnjqM2dbxoBQrx0Nrp0DQ”
[“object”]=>
string(15) “chat.completion”
[“created”]=>
int(1691027683)
[“model”]=>
string(18) “gpt-3.5-turbo-0613”
[“choices”]=>
array(1) {
[0]=>
array(3) {
[“index”]=>
int(0)
[“message”]=>
array(2) {
[“role”]=>
string(9) “assistant”
[“content”]=>
string(1323) “新宿は東京都内で最も繁華なエリアの一つです。駅周辺には高層ビルが立ち並び、多くの人が行き交います。新宿駅は日本でも最も利用者が多い駅の一つで、多くの鉄道路線が交差し、バスターミナルもあるため、アクセスが非常に便利です。

新宿には大型商業施設やデパート、ショッピングモールが集まっており、様々なショップやレストランがあります。また、歌舞伎町という繁華街もあり、夜になると多くの人々で賑わいます。歓楽街として知られており、多くの居酒屋、バー、クラブがあります。

また、新宿は文化施設も充実しており、新宿御苑や東京都庁舎、新宿中央公園などの公共の場所で自然に触れることもできます。さらに、新宿の西側には高層ビルが連なる都市の景色が楽しめる新宿西口地区もあります。

新宿はまた、交通の要所としても知られており、多くの人々が通勤や買い物などで訪れます。そのため、駅周辺は常に混雑していることが多いですが、多くの施設やイベントが盛り上がっているため、観光客や地元の人々にとっても魅力的な場所です。”
}
[“finish_reason”]=>
string(4) “stop”
}
}
[“usage”]=>
array(3) {
[“prompt_tokens”]=>
int(18)
[“completion_tokens”]=>
int(490)
[“total_tokens”]=>
int(508)
}
}

ChatGPTを動かしてみる

$ pip install openapi

import openapi

openai.api_key = '***'

response = openai.ChatCompletion.create(
	mmodel="gtp-3.5-turbo",
	messages=[
		{"role": "system", "content": "You are an assistant that knows a lot about animals."},
		{"role": "user", "content": "Tell me about elephants."},
	]

)
print(response['choices'][0]['message']['content'])

うーむ、なんか上手くいかんな

Rust 実行速度

use std::os::raw::c_int;

#[link(name="mylib", kind="static")]
extern "C" {
	fn twice(n: c_int) -> c_int;
}

fn main() {
	let n = 12;
	unsafe {
		println!("{}の2倍は{}", n, twice(n));
	}
}
use std::time::Instant;

fun main() {
	i16func();
	i64func();
}

fn i16func(){
	let mut v:16 = 0;
	let start = Instant::now();
	for _ in 0..1000 {
		for _ in 0..10000 {
			v = v + 1;
		}
		v = v - 10000;
	}
	let elepse = start.elapsed();
	println!("i16={:?}", v);
}

fn i64func() {
	let mut v:i64 = 0;
	let start = Instant::now();
	for _ in 0..1000 {
		for _ in 0..10000 {
			v = v + 1;
		}
		v = v- 10000;
	}
	let elepse = start.elapsed();
	println!("i64={:?}", v);
	println!("{}ミリ秒", elepse.as_millis());
}
use std::time::Instant;

fn main() {
	f32func();
	f64func();
}

fn f32func() {
	const NDATA:usize = 10000;
	let mut a:[f32; NDATA] = [0.0; NDATA];
	for i in 0..NDATA {
		a[i] = (NDATA - i) as f32;
	}
	println!("並び替えスタート");
	let start = Instant::now();
	for i in 0..NDATA{
		for j in 0..NDATA {
			if a[i] < a[j] {
				let tmp = a[i];
				a[i] = a[j];
				a[j] = tmp;
			}
		}
	}
	let elepse = start.elapsed();
	println!("並べ替え終了");
	println!("{}ミリ秒", elepse.as_millis());
}

fn f64func() {
	const NDATA:usize = 10000;
	let mut a:[f64; NDATA] = [0.0; NDATA];
	for i in 0..NDATA {
		a[i] = (NDATA - i) as f64;
	}
	let start = Instant::now();
	for i in 0..NDATA {
		for j in 0..NDATA {
			if a[i] < a[j] {
				let tmp = a[i];
				a[i] = a[j];
				a[j] = tmp;
			}
		}
	}
	let elepse = start.elapsed();
	println!("並び替え終了");
	println!("{}ミリ秒", elepse.as_millis());
}

Rust パニックとアサート

プログラムの実行が継続できないような重大な問題をパニックという
パニックは他の言語の例外処理に似ている
Cargo.tomlファイルのpanic=’abort’で異常終了する

let f = File::open("sample.txt");
let f = match f {
	Ok(file) => file,
	Err(error) => {
		panic!("ファイル開けません: {:?}", error)
	}
}

アサートはプログラムの途中で値が妥当であるか調べる
assert_eq!(left, right);

let f = 3.7_f64;

assert_eq!(f.floor(), 3.0);
println!("f={}", f);

### メモリ管理
メモリはランタイムが管理するので考える必要はない

Box: std::boxed::Boxを使うことでヒープにメモリを確保することができる

struct Point {
	x: i32,
	y: i32,
}

impl Clone for Poin {
	fn clone(&self) -> Self {
		Point {
			x: self.x.clone(),
			y: self.y.clone(),
		}
	}
}

fn main() {
	let p1 = Point {x: 12, y:25};
	let p2: Box<Point> = Box::new(Point {x: 23, y: 45});
	println!("{:?}", type_of(p1.clone()));
	println!("{:?}", type_of(p2.clone()));
	println!("{}, {}", p1.x, p1.y);
	println!("{}, {}", p2.x, p2.y);
}

fn type_of<T>(_: T) -> &'static str {
	std::any::type_name::<T>()
}
use std::mem;

struct Point {
	x: i32,
	y: i32,
}

fn main() {
	let p = Point {x: 12, y: 25};
	let a = [1,2,3,4,5,6,7,8,9];

	println!("pのサイズ={}", mem::size_of_val(&p));
	println!("aのサイズ={}", mem::size_of_val(&a));
}

Rust ネットワーク

TCPというプロトコルを使って情報を受け渡すサーバとクライアント

サーバ側

use std::net::{TcpListener,TcpStream};
use std::thread;
use std::io::{Read,Write,Error};

fn handle_data(mut stream: TcpStream) -> Result<(), Error> {
	println!("Connection from: {}", stream.peer_addr()?);
	let mut buf = [0; 512];
	loop {
		let byte_read = stream.read(&mut buf)?;
		for i in 0..byte_read {
			if buf[i] > 0x60 {
				buf[i] = buf[i] - 0x20;
			}
		}
		if byte_read == 0 {return Ok(());}
		stream.write(&buf[..byte_read])?;
	}
}

fn main() {
	let coninfo = "localhost:8000";
	let listener = TcpListener::bind(coninfo).expect("バインドできません。");
	for steam in listener.incoming(){
		match stream {
			Err(e) => {eprintln!("failed: {}", e)}
			Ok(stream) => {
				thread::spawn(move || {
					handle_data(stream).
						unwrap_or_else(|error| eprintln!("{:?}", error));
				});
			} 
		}
	}
}

クライアント側

use std::net::{TcpStream};
use std::str;
use std::io::{self,BufRead,BufReader,Write};

fn main() {
	let coinfo = "localhost:8000";

	let mut stream = TcpStream::connect(coinfo).expect("サーバに接続できません。");

	loop {
		let mut input = String::new();
		io::stdin().read_line(&mut input).expect("標準入力からの入力エラー");
		stream.write(input.as_bytes()).expect("サーバに送れません。");

		let mut reader = BufReader::new(&stream);
		reader.read_until(b'¥n', &mut buffer).expect("サーバから受け取れません");

		print!("{}", str::from_utf8(&buffer).expect("テキストを表示できません"));
	}
}

じゃんけんサーバ

use std::net::{TcpListener, TcpStream};
use std::thread;
use std::io::{Read,Write,Error};
use rand::{thread_rng, Rng};

fn handle_data(mut stream: TcpStream) -> Result<(), Error> {
	println!("Connection from: {}", stream.peer_addr()?);
	let mut buf = [0; 512];
	loop {
		let mut userte = false;
		let mut cpmsg = String::new();
		let mut msg = String::from("");
		let byte_read = stream.read(&mut buf)?;
		if byte_read == 0 {return Ok(());}

		let mut rng = thread_rng();
		let x: u16 = rng.gen_range(0, 3);

		match x {
			0 => cpmsg.insert_str(0, "私はグー"),
			1 => cpmsg.insert_str(0, "私はチョキ"),
			2 => cpmsg.insert_str(0, "私はパー"),
			_ => cpmsg.insert_str(0, ""),
		}
		let client_msg = String::from_utf8(buf.to_vec()).unwrap();
		msg.insert_str(0, &cpmsg);
		if client_msg.starts_with("グー") {
			userte=true;
			match x {
				0 => msg.push_str(":あいこ¥n");
				1 => msg.push_str(":あなたの勝ち¥n");
				2 => msg.push_str(":あなたの負け¥n");
				_ => ();
			}
		} else if client_msg.starts_with("チョキ"){
			userte=true;
			match x {
				0 => msg.push_str(":あなたの負け¥n");
				1 => msg.push_str(":あいこ¥n");
				2 => msg.push_str(":あなたの勝ち¥n");
				_ => ();
			}
		} else if client_msg.starts_with("パー"){
			userte=true;
			match x {
				0 => msg.push_str(":あなたの勝ち¥n");
				1 => msg.push_str(":あなたの負け¥n");
				2 => msg.push_str(":あいこ¥n");
				_ => ();
			}
		} if userte {
			let bytes = msg.as_bytes();
			let len = bytes.len();
			stream.write(&bytes[..len])?;
		} else {
			stream.write(&buf[..byte_read])?;
		}
		stream.flush()?;
	}
}

fn main() {
	let coninfo = "localhost:8000";
	let listener = TcpListener::bind(coninfo).expect("バインドできません。");
	for stream in listenr.incoming() {
		match stream {
			Err (e) => {eprintln!("failed: {}", e)}
			Ok(stream) => {
				thread::spawn(move || {
					handle_data(stream).
						unwrap_or_else(|error| eprintln!("{:?}", error));
				});
			}
		}
	}
}

Rust ファイル入出力

単純なファイル入出力はstd::fsやstd::ioにある関数を使う
std::fs::read(), std::fs::read_dir(), std::fs::read_to_string(), std::fs_write()

use std::fs;

fn main() {
	let result = fs::read_to_string("sample.txt");
	println!("{:?}", result);
}
use std::fs;

fn main() {
	match fs::read_to_string("sample.txt"){
		Ok(result) => println!("{}", result),
		Err(msg) => println!("エラー:{}", msg),
	}
}
use std::io::BufReader;
use std::io::prelude::*;
use std::fs::File;

fn main() -> std::io::Result<()> {
	let f = File::open("sample.txt")?;
	let reader = BufReader::new(f);

	for line in reader.lines() {
		println!("{}", line?);
	}
	Ok(())

}
use std::io;
use std::io::prelude::*;
use std::fs::File;

fn main() -> std::io::Result<()> {
	let mut f = File::open("sample.txt")?;
	let mut buffer = [0; 1000];

	let n = f.read(&mut buffer)?;

	println!("{:?}", &buffer[..n]);
	Ok(())
}
use std::fs::File;
use std::io::Write;

fn main() -> std::io::Result<()> {
	let txt = "こんにちは¥nHappy Rust¥n";
	let mut file = File::create("test.txt")?;
	write!(file, "{}", txt)?;
	file.flush()?;
	Ok(())

}
use std::fs::File;
use std::io::{Write, BufWriter};

fn main() -> std::io::Result<()> {
	let file = File::create("sample2.txt")?;
	let mut writer = BufWrite::new(file);
	let data:&str = "Hello¥nHappy Dogs";
	writer.write_all(data.as_bytes())?;
	writer.flush()?;
	Ok(())
}
use qrcode::QrCode;
use image::Luma;

fn main() {
	let code = QrCode::new(b"A0023213").unwrap();
	let image = code.render::<Luma<u8>>().build();

	image.save("sample.png").unwrap();
}

Rust ファイル操作

Rustのファイルシステムにアクセスするときは、std::fsモジュールにある関数を使うことができる
canonicalize(), copy(), create_dir(), create_dir_all(), hard_link(), metadata(), read_link(), remove_dir(), remove_dir_all(), remove_file(), rename(), set_permissions(), soft_link(), symlink_metadata()

pub fn copy>, Q: AsRef>(from: P, to: Q) -> Result

use std::env;
use std::fs;

fn main() -> std::io::Result<()> {
	let argv: Vec<String> = env::args().collect();
	let argc = argv.len();
	if argc < 3 {
		println!("引数を2個指定ください。");
		std::process::exit(1);
	}

	let src = &argv[1];
	let dest = &argv[2];
	fs::copy(src, dest)?;
	Ok(())
}
use std::fs;

fn main() -> std::io::Result<()> {
	fs::create_dir("./misc/subdir")?;
	Ok(())
}
use std::fs;
use std::path::PathBuf;

fn main() {
	let srcdir = PathBuf::from("./src");
	println!("{:?}", fs::canonicalize(&srcdir));
}

Rust 非同期実行

関数を非同期実行することができる
async/awaitは、時間のかかる処理をするときに、処理が終わるまでのスレッドを別のタスクの処理に使うことができる機能を提供する

use futures::executor::block_on;

fn wait() -> f64 {
	let mut x:f64 = 0.0;
	for _ in 1..10000 {
		for _ in 1..10000 {
			x = x * 1.001;
		}
	}
	x
}

async fn print_dot(){
	println!(".");
}

async fn print_plus(){
	plusfunc().await;
}

async fn print_minus() {
	wait();
	println!("-");
}

async fn plusfunc(){
	wait();
	println!("+");
}

async fn async_main() {
	let f1 = print_plus();
	let f2 = print_minus();
	let f3 = print_dot();
	println!("Hello");
	futures::join!(f1, f2, f3);
}

fn main(){
	block_on(async_main());
}