【Rust】シャミアの秘密計算(SSS)をRustで動かしてみる

private keyを複数のシェアに分割して、それをrestoreして元のprivate keyに戻すということは割と簡単にできそうではある。

shamirsecretsharing = “0.1.5”

use shamirsecretsharing::*;

async fn main()  {

    let private_key = "i3HdSBYb5fmuD4RxAf77VnYbyAy6b8ab5LEddfQLM2VaYrUUFNNp6Pk22dsTAibj".to_string();
    let data = private_key.into_bytes();
    println!("{:?}", data);

    let count = 3;
    let treshold = 2;
    let mut shares = create_shares(&data, count, treshold).unwrap();
    
    for share in shares.clone() {
        print_base_encode(share);
    }

    let restored = combine_shares(&shares.clone()).unwrap();
    println!("{:?}", String::from_utf8(restored.unwrap()).unwrap());
}

fn print_base_encode(s: Vec<u8>) {
    // println!("{:?}", s.clone());
    let base64_encoded = base64::encode(&s);
    println!("base64 encoded: {}", base64_encoded);
    // println!("{:?}", BASE64_STANDARD.decode(base64_encoded).unwrap());
}

base64 encoded: AZv7eBLYhiBxgjpD3kI0YbLnnC88DnTWPghszvPWHLt4D+dFwsC4CE7R2mlSAlDsuituyPlTHSzE7rSNJylQvj1kn7sHEhEDqxC5b0qEj0SjfkVoaPcgdXdHOmX8rhOjO+xy9n5qlHpAcLJDHLcj2hA=

base64 encoded: AhM+urNxZnzJsekDjygSpCqresvZz1Kg/zFE8/zdbLkWD+dFwsC4CE7R2mlSAlDsuituyPlTHSzE7rSNJylQvj1kn7sHEhEDqxC5b0qEj0SjfkVoaPcgdXdHOmX8rhOjO+xy9n5qlHpAcLJDHLcj2hA=

base64 encoded: A2t9DSUWz0ihoFHKSQ7556tm0Zdzebl7SSZcEfkttU7FD+dFwsC4CE7R2mlSAlDsuituyPlTHSzE7rSNJylQvj1kn7sHEhEDqxC5b0qEj0SjfkVoaPcgdXdHOmX8rhOjO+xy9n5qlHpAcLJDHLcj2hA=
“i3HdSBYb5fmuD4RxAf77VnYbyAy6b8ab5LEddfQLM2VaYrUUFNNp6Pk22dsTAibj”

【Python】シャミアの秘密計算

import random
from typing import List, Tuple

def generate_coefficients(secret: int, threshold: int) -> List[int]:
    coefficients = [secret]
    for _ in range(threshold - 1):
        coefficients.append(random.randint(1, 256))
    return coefficients

def create_shares(
    secret: int, total_shares: int, threshold: int
) -> List[Tuple[int, int]]: 
    coefficients = generate_coefficients(secret, threshold)
    shares = []
    for x in range(1, total_shares + 1):
        y = sum(coeff * (x**exp) for exp, coeff in enumerate(coefficients))
        shares.append((x, y))
    return shares

def reconstruct_secret(shares: List[Tuple[int, int]], threshold: int) -> int:
    def _lagrange_interpolation(x: int, x_s: List[int], y_s: List[int]) -> int:
        def _basis(j: int) -> int:
            num = 1
            den = 1
            for m in range(len(x_s)):
                if m != j:
                    num *= x - x_s[m]
                    den *= x_s[j] - x_s[m]
            return num // den

        result = 0
        for j in range(len(y_s)):
            result += y_s[j] * _basis(j)
        return result

    x_s, y_s = zip(*shares)
    return _lagrange_interpolation(0, x_s, y_s)

if __name__ == "__main__":
    secret = 2732
    total_shares = 5
    threshold = 2

    shares = create_shares(secret, total_shares, threshold)
    print("shares:", shares)

    selected_shares = shares[:threshold]
    print(zip(*selected_shares))
    x_s, y_s = zip(*selected_shares)
    print(x_s, y_s)
    recovered_secret = reconstruct_secret(selected_shares, threshold)
    print("Recovered Secret:", recovered_secret)

$ python3 test.py
shares: [(1, 2961), (2, 3190), (3, 3419), (4, 3648), (5, 3877)]

(1, 2) (2961, 3190)
Recovered Secret: 2732

【Rust】reqwestによるPostのレスポンスタイムの差

幾つかのサイトにデータをPostして、レスポンスタイムに差があるかを調査する。

    let now = time::Instant::now();
    let mut post_url = format!("http://www.jsontest.com/");
    let client = reqwest::Client::new();
    let resp = client.post(post_url)
        .header(reqwest::header::CONTENT_TYPE, "application/json")
        .json(&str)
        .send()
        .await
        .unwrap();
    println!("{:?}", resp);
    println!("{:?}", now.elapsed());

↓レスポンスタイムの差

同じサーバ内
67.997892ms
76.798063ms
73.945108ms

http://httpbin.org/post
626.023117ms
560.575466ms
1.050126063s

https://dummyjson.com/posts
695.071869ms
825.34323ms
676.196368ms

http://www.jsontest.com/
229.820077ms
256.854971ms
203.667686ms

当たり前だが、同じサーバ内のレスポンスは早い。
それ以外でも、サイトごとによって、レスポンスタイムが早いものと遅いものの違いが生じている。
なるほど、なかなか面白いね。

【PSQL16】Ident authentication failed for user “postgres”

以下のようなエラーが出る時
$ python3 migration.py
Traceback (most recent call last):
File “/home/ec2-user/cmc_test/assets/migration.py”, line 8, in
connection = psycopg2.connect(
File “/home/ec2-user/cmc_test/venv/lib64/python3.9/site-packages/psycopg2/__init__.py”, line 122, in connect
conn = _connect(dsn, connection_factory=connection_factory, **kwasync)
psycopg2.OperationalError: connection to server at “localhost” (127.0.0.1), port 5432 failed: FATAL: Ident authentication failed for user “postgres”

sudo vi /var/lib/pgsql/data/pg_hba.conf
identからtrustに変更します。

# IPv4 local connections:
# host    all             all             127.0.0.1/32            ident
host    all             all             127.0.0.1/32            trust

$ sudo service postgresql restart
$ python3 migration.py

ふぅ~

【Ubuntu】conoha VPSのport開放の設定

conohaコンソール側のセキュリティグループで指定したポートを開放してもアクセスできない時。
Ubuntu側の設定を確認する。

# sudo ufw status
Status: active

To Action From
— —— —-
OpenSSH ALLOW Anywhere
OpenSSH (v6) ALLOW Anywhere (v6)

OpenSSHしか許可されていないので、開放したいportを追加する。
# sudo ufw allow 3000/tcp
Rule added
Rule added (v6)

# sudo ufw status
Status: active

To Action From
— —— —-
OpenSSH ALLOW Anywhere
3000/tcp ALLOW Anywhere
OpenSSH (v6) ALLOW Anywhere (v6)
3000/tcp (v6) ALLOW Anywhere (v6)

焦った……

【Rust】バイト列からリトルエンディアンへの変換

    let s = "sato".to_string().into_bytes();
    println!("{:?}", s);
    let l = LittleEndian::read_u32(&s);
    println!("{}", l);
    let b = BigEndian::read_u32(&s);
    println!("{}", b);

    let mut wtr = vec![];
    wtr.write_u32::<LittleEndian>(l).unwrap();
    println!("{:?}", wtr);

[115, 97, 116, 111]
1869898099
1935766639
[115, 97, 116, 111]

構造体をバイト列にする

#[derive(Serialize, Deserialize, Debug)]
struct Name {
    family: Vec<u8>,
    first: Vec<u8>,
}

    let name1 = Name {family: "sato".to_string().into_bytes(), first: "taro".to_string().into_bytes()};
    println!("{:?}", name1);
    let family = String::from_utf8(name1.family).unwrap();
    println!("{}", family);

Name { family: [115, 97, 116, 111], first: [116, 97, 114, 111] }
sato

なるほどー 前処理、後処理が多くなるが、安全性は高まりそう。

【Rust】github actions

.github/workflows内にymlファイルを設置し、Workflowを書く
push, pull_request, deployment, release, issues, scheduleなどのイベントがよく使われる

チュートリアルのコード

name: GitHub Actions Demo
run-name: ${{ github.actor }} is testing out GitHub Actions 🚀
on: [push]
jobs:
  Explore-GitHub-Actions:
    runs-on: ubuntu-latest
    steps:
      - run: echo "🎉 The job was automatically triggered by a ${{ github.event_name }} event."
      - run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by GitHub!"
      - run: echo "🔎 The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}."
      - name: Check out repository code
        uses: actions/checkout@v4
      - run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner."
      - run: echo "🖥️ The workflow is now ready to test your code on the runner."
      - name: List files in the repository
        run: |
          ls ${{ github.workspace }}
      - run: echo "🍏 This job's status is ${{ job.status }}."

### 実際に何を書くか
build
test
lint
Type

Unit Testを実行して、Clippyを確認する

name: GitHub Actions CI
run-name: Testing out 🚀
on: [push]
jobs:
  GitHub-Actions-Check:
    runs-on: ubuntu-latest
    steps:
      - name: Check out repository code
        uses: actions/checkout@v4
      - name: List files in the repository
        run: |
          ls
      - name: Build
        run: |
          cargo build
      - name: Test
        run: |
          cargo test
      - name: Clippy
        run: |
          rustup component add clippy
          cargo clippy

【Rust】reqwest Postのレスポンス(body payload)を表示する

“{:?}”, resp だとstatusだが、resp.text().await.unwrap()とすると、bodyを表示できる。

    let mut post_url = format!("http://192.168.33.10:3000/health");
    let client = reqwest::Client::new();
    let resp = client.post(post_url)
        .header(reqwest::header::CONTENT_TYPE, "application/json")
        .json(&str)
        .send()
        .await
        .unwrap();
    println!("{:?}", resp);
    println!("{}", resp.text().await.unwrap());

Finished `dev` profile [unoptimized + debuginfo] target(s) in 7.43s
Running `target/debug/axum`
Response { url: Url { scheme: “http”, cannot_be_a_base: false, username: “”, password: None, host: Some(Ipv4(192.168.33.10)), port: Some(3000), path: “/health”, query: None, fragment: None }, status: 200, headers: {“content-type”: “text/plain; charset=utf-8”, “content-length”: “8”, “date”: “Thu, 13 Mar 2025 13:44:24 GMT”} }
All good

【Rust】tokio::spawnのawait

下のように書くと、DNSエラーとなる。

#[tokio::main]
async fn main()  {
    let res = tokio::spawn(async move {
        let v = get_myip().await.unwrap();
        println!("{}", v);
    });    
}   

pub async fn get_myip() -> Result<String, Box<dyn std::error::Error>> {

    let ip: Ip = serde_json::from_str(&reqwest::get("https://httpbin.org/ip")
        .await?
        .text()
        .await?)?;
    Ok(ip.origin)
}

しかし、実行されるまで待って、res.await.unwrap();とすれば、エラーは解消される。

    let res = tokio::spawn(async move {
        let v = get_myip().await.unwrap();
        println!("{}", v);
    });
    res.await.unwrap();

レスポンスがないままtokio::spawnが終了してしまうからっぽい。
うーん、奥が深い… httpbin.org に問題があるかと思ったけど、全然違った…