愛記システムの基本設計:DApps側である愛記システム 要件定義について③ | 続・ティール組織 研究会のブログ

続・ティール組織 研究会のブログ

ティール組織が話題になっているが、具現化するにはどうしたらよいか?
その研究を続けるにあたり、さらに次の形態である、続・ティール組織なるものまで視野に入れ、具体的な施策・行動内容を研究・支援する会。

先までは、"愛記"についての記載で、どのようにブロックチェーンSNSに組み込んで実装していけばよいのか、概念的なところからアプローチ方法を記載していった。概念設計としてはひとまず終えた。次は、フェデレーションモデル全体の基本設計といえるところまで、基本設計書に着手できるようなところまで、概念を具体化していきたい。そして、それにつながるDApps側である「愛記システム」を、Pythonプログラムで開発していきたい。

 

愛の行動のPL,BSを決算書として、個人単位、市町村単位、で公表するような愛記システムというものを考えている。愛の行動のデータベースはブロックチェーンのプログラムであり、日々の愛の行動による愛貨の移動を決算書にまとめていきたい。なお、市町村のブロックチェーンのプログラムは以前にも記載している。その市町村のブロックチェーンのプログラムにつながる愛記システムを、DApps側であるPythonプログラムとして設計したい。その場合、基本設計をどのような手順で進めていけばよいか、詳しく見ていこう。

 

愛記システムを設計するための基本手順を以下に示す。このシステムは、Pythonを用いて市町村のブロックチェーンと連携し、個人および市町村単位での愛の行動のデータを収集、記録し、決算書(PL、BS)として公表するものである。

基本設計のステップ

  1. 要件定義
  2. アーキテクチャ設計
  3. データベース設計
  4. API設計
  5. ブロックチェーンインターフェース
  6. 決算書の生成
  7. フロントエンド開発
  8. テストとデプロイ

基本設計の各ステップを順番に進めることで、ブロックチェーンとDAppsとして繋がる「愛記システム」の詳細な設計が可能になる。各ステップでは、関係者との協議やレビューを通じて設計内容を確定していくことが重要である。

1.要件定義

まず、基本設計の最初のステップである要件定義をしていきたい。どのような機能が必要か、どのような問題を解決するのかを洗い出したい。要件定義はシステム設計の最初の重要なステップであり、システムが解決するべき問題と、必要な機能を明確に定義するプロセスである。以下に、愛記システムのプログラムに必要な機能と解決すべき問題を列挙してみよう。

機能要件

  1. 愛の行動の記録

  2. 愛貨の移動の記録

  3. 決算書の生成

  4. 個人および市町村単位でのデータの集約

  5. データのブロックチェーンへの記録と取得

  6. 愛貨の管理

  7. ユーザー管理

  8. 通知機能

  9. レポート機能

  10. ダッシュボード

非機能要件

  1. セキュリティ

  2. 可用性

  3. パフォーマンス

  4. スケーラビリティ

  5. ユーザビリティ

  6. コンプライアンス

解決すべき問題

  1. 透明性と信頼性の確保

  2. データの一元管理

  3. 愛の行動の促進

  4. 評価制度の確率

  5. データのセキュリティとプライバシーの保護

これらの要件を基に、愛記システムの基本設計を進めていくことが重要である。次のステップでは、これらの要件を具体的なアーキテクチャ設計に反映していくことになる。まずは、要件定義の解決すべき問題を一つずつクリアにしていきたい。

透明性と信頼性の確保

愛貨の取引と愛の行動の記録を透明にし、信頼性を確保することが重要だ。以下に、具体的な項目とその決定プロセスを記載する。

・透明性と信頼性の確保に必要な項目と決定プロセス

1. データの完全性と一貫性の保証

  • データの完全性: すべての取引と愛の行動記録が正確かつ改ざんされていないことを保証する。

  • データの一貫性: システム全体でデータが統一されていることを確認する。

2. 取引の透明性の確保

  • 公開取引データ: 取引データを公開し、誰でも確認できるようにする。

  • 監査ログ: 取引や行動のすべての変更履歴を保持し、監査可能にする。

3. データのセキュリティとプライバシー保護

  • 暗号化: データの送受信時および保存時に暗号化を行い、データの安全性を確保。

  • アクセス制御: データへのアクセスを制御し、必要な権限を持つユーザーのみに限定。

4. 取引の正当性の確認

  • 署名の生成と検証: 取引データの署名を生成し、取引の正当性を検証。

  • 取引の検証: 各取引を検証し、不正行為や二重支出を防止。

これらの項目を詳細に決定し、実装することで、愛記システムの透明性と信頼性を確保することができる。各項目については、具体的な技術要件や設計仕様を定義し、システム開発の各フェーズで反映させることが重要である。

 

・データの完全性について

まずはデータの完全性についてから順番に見ていこう。

項目: 取引ID、日時、送信者、受信者、愛貨の量、取引の内容、署名、ハッシュ値というが、いままで概念設計で記載してきた愛記システム、愛貨のやりとり、愛記の決算書を振り返ってみて、取引データは、取引ID、日時、送信者、受信者、愛貨の量、取引の内容、署名、ハッシュ値だけでいいのか、もっとたくさんあるのではと思ったので、今一度、取引データを検証してみる。前回の続きを記載する。

・取引データの完全性を保証するための詳細な項目

  1. 取引ID (Transaction ID)

  2. 日時 (Timestamp)

  3. 送信者 (Sender)

  4. 受信者 (Receiver)

  5. 愛貨の量 (Amount of Love Tokens)

  6. 取引の内容 (Transaction Content)

    • 取引の具体的な内容や目的。
    • 例: 「ゴミ出しの手伝い」「地域清掃活動への参加」。

      愛貨のやりとりの際に、愛の行動レベル、愛の行動レベルに相当する愛貨の種類(AIR、AIS・・・)、取引内容というものが記録される。その際の取引内容なのだが、フリーワードでいちいち入力して貰うようにすると面倒でたまらない。かといって、リストから選択させようにも、愛の行動の種類は多数ある。そこで、損益計算書の仕訳科目である代表的な愛の行動内容をリストにしておき、まずはそこから選択させ、その後、詳細があればフリーワードで記入して貰うことにする。このようなプログラムに設計したい場合、どのようになるか以下に示してみよう。

    • データベース設計

      • actionsテーブルに代表的な愛の行動内容を事前に登録しておく。
      • transactionsテーブルに取引内容のフィールドを追加。
        ・SQLで表示
        CREATE TABLE actions (
            id SERIAL PRIMARY KEY,
            description VARCHAR(255) NOT NULL,
            level INT NOT NULL,
            category VARCHAR(50) NOT NULL
        );

        CREATE TABLE transactions (
            id SERIAL PRIMARY KEY,
            transaction_id VARCHAR(36) NOT NULL,
            timestamp TIMESTAMP NOT NULL,
            sender_id VARCHAR(50) NOT NULL,
            receiver_id VARCHAR(50) NOT NULL,
            action_id INT NOT NULL,
            token_type VARCHAR(10) NOT NULL,
            amount DECIMAL(10, 2) NOT NULL,
            signature VARCHAR(64) NOT NULL,
            region_id VARCHAR(50),
            municipality_id VARCHAR(50),
            content VARCHAR(255),
            FOREIGN KEY (action_id) REFERENCES actions (id)
        );

        ・サンプルデータ挿入
        INSERT INTO actions (description, level, category) VALUES
        ('ゴミ出しの手伝い', 1, '家庭支援'),
        ('地域清掃活動への参加', 2, '地域貢献'),
        ('老人ホームでのボランティア', 3, '福祉支援'),
        ('子供の宿題を手伝う', 4, '教育支援'),
        ('地域のイベントをサポート', 5, 'イベント支援'),
        ('地域のスポーツイベントに参加', 6, 'スポーツ振興'),
        ('環境保護活動に参加', 7, '環境保護'),
        ('友人の引っ越しを手伝う', 8, '友人支援'),
        ('地域の文化イベントを支援', 9, '文化支援'),
        ('災害支援活動に参加', 10, '災害支援');
         
    • API設計

      • GET /actions: 代表的な愛の行動内容を取得するエンドポイント。
      • POST /transactions: 取引の記録エンドポイントに取引内容のフィールドを追加。
        ・エンドポイントの実装(Flask)
        from flask import Flask, request, jsonify
        import uuid
        import datetime
        import hashlib

        app = Flask(__name__)

        # データベースのモック
        users = {}
        transactions = []
        actions = [
            {'id': 1, 'description': 'ゴミ出しの手伝い', 'level': 1, 'category': '家庭支援'},
            {'id': 2, 'description': '地域清掃活動への参加', 'level': 2, 'category': '地域貢献'},
            # その他のアクションも追加
        ]

        # 代表的な愛の行動内容を取得するエンドポイント
        @app.route('/actions', methods=['GET'])
        def get_actions():
            return jsonify(actions)

        # ユーザー登録エンドポイント
        @app.route('/users', methods=['POST'])
        def register_user():
            data = request.json
            user_id = f"{data['region_id']}-{data['municipality_id']}-{str(uuid.uuid4())[:8]}"
            users[user_id] = {
                'name': data['name'],
                'email': data['email'],
                'public_key': data['public_key'],
                'private_key': data['private_key']
            }
            return jsonify({'status': 'success', 'user_id': user_id})

        # 取引記録エンドポイント
        @app.route('/transactions', methods=['POST'])
        def create_transaction():
            data = request.json
            transaction_id = str(uuid.uuid4())
            timestamp = datetime.datetime.now().isoformat()
            signature_content = f"{transaction_id}{timestamp}{data['sender_id']}{data['receiver_id']}{data['action_id']}{data['token_type']}{data['amount']}{data['signature']}"
            signature = hashlib.sha256(signature_content.encode()).hexdigest()

            transaction = {
                'transaction_id': transaction_id,
                'timestamp': timestamp,
                'sender_id': data['sender_id'],
                'receiver_id': data['receiver_id'],
                'action_id': data['action_id'],
                'token_type': data['token_type'],
                'amount': data['amount'],
                'signature': signature,
                'region_id': data.get('region_id'),
                'municipality_id': data.get('municipality_id'),
                'content': data.get('content', '')
            }
            transactions.append(transaction)
            return jsonify({'status': 'success', 'transaction_id': transaction_id})

        # 取引取得エンドポイント
        @app.route('/transactions', methods=['GET'])
        def get_transactions():
            user_id = request.args.get('user_id')
            user_transactions = [tx for tx in transactions if tx['sender_id'] == user_id or tx['receiver_id'] == user_id]
            return jsonify({'transactions': user_transactions})

        # トークン価格取得エンドポイント
        @app.route('/token_prices', methods=['GET'])
        def get_token_prices():
            return jsonify(token_prices)

        if __name__ == '__main__':
            app.run(debug=True)
         
    • フロントエンド設計

      • 代表的な愛の行動内容をリストで表示し、選択させる。
      • 詳細がある場合はフリーワードで入力できるフォームを提供。
        <!DOCTYPE html>
        <html>
        <head>
            <title>愛記システム</title>
            <script>
                async function submitTransaction() {
                    const senderId = document.getElementById("sender_id").value;
                    const receiverId = document.getElementById("receiver_id").value;
                    const actionId = document.getElementById("action_id").value;
                    const tokenType = document.getElementById("token_type").value;
                    const amount = document.getElementById("amount").value;
                    const signature = document.getElementById("signature").value;
                    const content = document.getElementById("content").value;

                    const response = await fetch('/transactions', {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json'
                        },
                        body: JSON.stringify({
                            sender_id: senderId,
                            receiver_id: receiverId,
                            action_id: actionId,
                            token_type: tokenType,
                            amount: amount,
                            signature: signature,
                            content: content
                        })
                    });

                    const data = await response.json();
                    console.log(data);
                }

                async function getActions() {
                    const response = await fetch('/actions');
                    const data = await response.json();
                    const actionSelect = document.getElementById("action_id");

                    data.forEach(action => {
                        const option = document.createElement("option");
                        option.value = action.id;
                        option.text = action.description;
                        actionSelect.add(option);
                    });
                }

                async function getTokenPrices() {
                    const response = await fetch('/token_prices');
                    const data = await response.json();
                    console.log(data);
                    // Update UI with token prices
                }

                window.onload = function() {
                    getActions();
                    getTokenPrices();
                }
            </script>
        </head>
        <body>
            <h1>愛記システム</h1>
            <form onsubmit="submitTransaction(); return false;">
                <label for="sender_id">Sender ID:</label>
                <input type="text" id="sender_id" name="sender_id"><br>
                <label for="receiver_id">Receiver ID:</label>
                <input type="text" id="receiver_id" name="receiver_id"><br>
                <label for="action_id">Action:</label>
                <select id="action_id" name="action_id"></select><br>
                <label for="token_type">Token Type:</label>
                <input type="text" id="token_type" name="token_type"><br>
                <label for="amount">Amount:</label>
                <input type="text" id="amount" name="amount"><br>
                <label for="signature">Signature:</label>
                <input type="text" id="signature" name="signature"><br>
                <label for="content">Content (optional):</label>
                <input type="text" id="content" name="content"><br>
                <input type="submit" value="Submit Transaction">
            </form>
            <button onclick="getTokenPrices()">Get Token Prices</button>
        </body>
        </html>
         
    • 説明:
      フロントエンド: ユーザーが取引を入力するためのフォームを提供する。代表的な愛の行動内容は、<select>要素として表示され、ユーザーは選択できます。詳細な内容をフリーワードで入力するためのフィールドも提供する。

    • バックエンド: Flaskを使用してAPIエンドポイントを実装する。取引記録、ユーザー登録、取引取得、トークン価格取得の各エンドポイントを提供する。
       
  7. 署名 (Signature)

    Rustコード(ラティス暗号を使用)

    • 取引データを送信者がデジタル署名したもの。
    • 例: デジタル署名アルゴリズムを用いた署名データ。

      愛貨のやり取り時に、量子コンピュータ時代が到来しても耐えられるような署名を設計したい。量子コンピュータ時代に対応する量子鍵や署名を設計するためには、次世代の暗号技術を利用する必要がある。具体的には、ラティス暗号やマルチバリアント公開鍵暗号などが候補となる。ここでは、ラティス暗号を基にしたデジタル署名の例を示す。

      ・ラティス暗号によるデジタル署名の概要

    • 鍵生成 (Key Generation):
      • 秘密鍵と公開鍵を生成します。
    • 署名生成 (Signature Generation):
      • 秘密鍵を使用してメッセージの署名を生成します。
    • 署名検証 (Signature Verification):
      • 公開鍵を使用して署名の有効性を検証します。
    • ラティス暗号を用いたデジタル署名のブロックチェーンへの実装例

      以下に、ブロックチェーンのプログラムRustでのラティス暗号を用いたデジタル署名生成および検証の例を示す。Rustでは、適切なライブラリが必要となるが、ここでは簡易的な例を手動で実装する。まず、以下のコマンドで必要なクレートを追加する。
      [dependencies]
      rand = "0.8"
      sha2 = "0.10"

      次に、以下にRustコードを示す。
      extern crate rand;
      extern crate sha2;

      use rand::Rng;
      use rand::distributions::Uniform;
      use sha2::{Sha256, Digest};

      #[derive(Debug)]
      struct LatticePublicKey {
          A: Vec<Vec<i32>>,
          t: Vec<i32>,
      }

      #[derive(Debug)]
      struct LatticePrivateKey {
          s: Vec<i32>,
      }

      #[derive(Debug)]
      struct LatticeSignature {
          y: Vec<i32>,
      }

      const N: usize = 512;
      const Q: i32 = 1024;

      // ランダム行列生成関数
      fn generate_random_matrix(n: usize, q: i32) -> Vec<Vec<i32>> {
          let mut rng = rand::thread_rng();
          let between = Uniform::from(-q / 2..q / 2);
          (0..n).map(|_| (0..n).map(|_| rng.sample(&between)).collect()).collect()
      }

      // ランダムベクトル生成関数
      fn generate_random_vector(n: usize, q: i32) -> Vec<i32> {
          let mut rng = rand::thread_rng();
          let between = Uniform::from(-q / 2..q / 2);
          (0..n).map(|_| rng.sample(&between)).collect()
      }

      // 鍵生成関数
      fn generate_keypair(n: usize, q: i32) -> (LatticePublicKey, LatticePrivateKey) {
          let A = generate_random_matrix(n, q);
          let s = generate_random_vector(n, q);
          let e = generate_random_vector(n, q);
          let t = (0..n).map(|i| (0..n).map(|j| A[i][j] * s[j]).sum::<i32>() + e[i]).collect();
          let public_key = LatticePublicKey { A, t };
          let private_key = LatticePrivateKey { s };
          (public_key, private_key)
      }

      // 署名生成関数
      fn sign_message(private_key: &LatticePrivateKey, message: &Vec<u8>, q: i32) -> LatticeSignature {
          let s = &private_key.s;
          let e_prime = generate_random_vector(s.len(), q);
          let y = (0..s.len()).map(|i| s[i] * message[i] as i32 + e_prime[i]).collect();
          LatticeSignature { y }
      }

      // 署名検証関数
      fn verify_signature(public_key: &LatticePublicKey, message: &Vec<u8>, signature: &LatticeSignature, q: i32) -> bool {
          let A = &public_key.A;
          let t = &public_key.t;
          let y = &signature.y;
          let left_side: Vec<i32> = (0..A.len()).map(|i| (0..A.len()).map(|j| A[i][j] * y[j]).sum::<i32>()).collect();
          let right_side: Vec<i32> = (0..t.len()).map(|i| t[i] * message[i] as i32).collect();
          left_side.iter().zip(right_side.iter()).all(|(&l, &r)| l % q == r % q)
      }

      // メッセージのハッシュ化
      fn hash_message(message: &str) -> Vec<u8> {
          let mut hasher = Sha256::new();
          hasher.update(message);
          hasher.finalize().to_vec()
      }

      // メイン関数
      fn main() {
          // 鍵ペア生成
          let (public_key, private_key) = generate_keypair(N, Q);

          // メッセージ
          let message = "愛の行動を記録するメッセージ";
          let hashed_message = hash_message(message);

          // 署名生成
          let signature = sign_message(&private_key, &hashed_message, Q);
          println!("Signature: {:?}", signature.y);

          // 署名検証
          let is_valid = verify_signature(&public_key, &hashed_message, &signature, Q);
          println!("Signature valid: {}", is_valid);
      }
       

      ・説明:
    • 依存クレートのインポート:

      • rand クレートを用いて乱数生成を行い、sha2 クレートを用いてSHA-256ハッシュを計算する。
    • 構造体の定義:

      • LatticePublicKey, LatticePrivateKey, LatticeSignature の各構造体を定義する。
    • 乱数行列と乱数ベクトルの生成:

      • generate_random_matrix と generate_random_vector 関数で、ラティス暗号のパラメータを生成する。
    • 鍵生成関数:

      • generate_keypair 関数で公開鍵と秘密鍵のペアを生成する。
    • 署名生成関数:

      • sign_message 関数でメッセージの署名を生成する。
    • 署名検証関数:

      • verify_signature 関数で署名の検証を行う。
    • メッセージのハッシュ化:

      • hash_message 関数でメッセージをSHA-256でハッシュ化する。
    • メイン関数:

      • 鍵ペアの生成、メッセージの署名生成と検証を行う。
    • このように、Rustでラティス暗号を用いたデジタル署名を実装し、DApps側での署名生成と検証を行うことができる。
       
    • ラティス暗号を用いたデジタル署名のDApps側への実装例
    • DApps側でのPythonプログラムにおいても、ブロックチェーン側であるRustプログラムにおいても、両方においてデジタル署名を生成および検証する必要があり取引の署名や検証は重要である。DAppsでは、愛貨の取引が発生する際に、ユーザーがデジタル署名を生成し、その署名を取引データとともに送信する必要がある。また、受信者側では、その署名の検証を行う。

      1. 全体のフローと役割

      ・ブロックチェーン側(Rustプログラム)

    • 役割: 取引の記録、検証、ブロックの生成など、ブロックチェーンの基本的な機能を提供する。ネットワーク全体で一貫したデータの整合性を保つために、各取引の署名検証を行う。
    • 署名検証: 取引がブロックチェーンに追加される前に、取引データと署名の検証を行う。これにより、取引が改ざんされていないことを確認する。

      ・DApps側(Pythonプログラム)
    • 役割: ユーザーが取引を作成し、それをブロックチェーンに送信するためのインターフェースを提供する。ユーザーのプライベートキーを使用して取引に署名する。
    • 署名生成: ユーザーが取引を作成した際に、その取引に対してデジタル署名を生成する。この署名は、後でブロックチェーン側で取引が検証される際に使用される。
    • 2. 具体的な流れ

    • ユーザーがDAppsを使用して取引を作成:

      • Pythonプログラムを使用して、取引データを生成する。
      • ユーザーのプライベートキーで取引データのハッシュに署名を生成する。
      • 取引データと署名をブロックチェーンに送信する。
    • ブロックチェーン側で取引を受け取る:

      • RustプログラムがDAppsから送信された取引データと署名を受け取る。
      • 取引データのハッシュを計算し、受け取った署名を検証する。
      • 署名が正しければ、その取引をブロックに追加する。
    • 3. 例の具体的な結びつき

      DApps側で取引の署名を生成し、それをブロックチェーン側で検証する具体的な流れをコードに組み込んでみよう。以下に、DApps側での署名生成と検証を含む愛貨取引のPythonプログラムの設計案を示す。

      ・Pythonプログラムの例
      import numpy as np
      import hashlib
      import json
      from datetime import datetime
      from secrets import randbelow

      # ランダム行列生成関数
      def generate_random_matrix(n, q):
          return np.random.randint(-q // 2, q // 2, size=(n, n))

      # ランダムベクトル生成関数
      def generate_random_vector(n, q):
          return np.random.randint(-q // 2, q // 2, size=n)

      # 鍵の生成
      def generate_keys(n, q):
          A = generate_random_matrix(n, q)
          s = generate_random_vector(n, q)
          e = generate_random_vector(n, q)
          t = np.dot(A, s) + e
          public_key = {'A': A, 't': t}
          private_key = {'s': s}
          return public_key, private_key

      # メッセージのハッシュ化
      def hash_message(message):
          message_bytes = json.dumps(message, sort_keys=True).encode('utf-8')
          return hashlib.sha256(message_bytes).hexdigest()

      # 署名の生成
      def sign_message(private_key, message_hash, q):
          s = private_key['s']
          e_prime = generate_random_vector(len(s), q)
          y = s * int(message_hash, 16) + e_prime
          return y

      # 署名の検証
      def verify_signature(public_key, message_hash, signature, q):
          A = public_key['A']
          t = public_key['t']
          y = signature
          left_side = np.dot(A, y) % q
          right_side = (t * int(message_hash, 16)) % q
          return np.allclose(left_side, right_side)

      # 取引の作成
      def create_transaction(sender_id, receiver_id, amount, action_content, private_key, q):
          timestamp = datetime.utcnow().isoformat()
          transaction = {
              "transaction_id": str(hashlib.sha256((sender_id + receiver_id + timestamp).encode('utf-8')).hexdigest()),
              "timestamp": timestamp,
              "sender_id": sender_id,
              "receiver_id": receiver_id,
              "amount": amount,
              "action_content": action_content
          }
          transaction_hash = hash_message(transaction)
          signature = sign_message(private_key, transaction_hash, q)
          transaction['signature'] = signature.tolist()
          return transaction

      # 取引の送信
      def send_transaction(transaction, node_url):
          headers = {'Content-Type': 'application/json'}
          response = requests.post(node_url, data=json.dumps(transaction), headers=headers)
          return response.json()

      # メイン関数
      def main():
          n = 512
          q = 1024
          # 鍵の生成(実際のアプリケーションでは鍵は事前に生成・保存される)
          public_key, private_key = generate_keys(n, q)
          sender_id = np.random.randint(0, 1000000)  # 一意の送信者ID(例としてランダム値を使用)
          receiver_id = np.random.randint(0, 1000000)  # 一意の受信者ID(例としてランダム値を使用)

          # 取引の作成
          transaction = create_transaction(sender_id, receiver_id, 10, "ゴミ出しの手伝い", private_key, q)

          # 取引の送信
          node_url = "http://localhost:5000/transactions"
          response = send_transaction(transaction, node_url)
          print(response)

      if __name__ == "__main__":
          main()
       

      ・説明

    • generate_random_matrix: ランダムな行列を生成する。
    • generate_random_vector: ランダムなベクトルを生成する。
    • generate_keys: ラティス暗号の公開鍵と秘密鍵を生成する。
    • hash_message: メッセージをSHA-256でハッシュ化する。
    • sign_message: メッセージハッシュに基づいて署名を生成する。
    • verify_signature: 署名の検証を行う。
    • create_transaction: 取引を作成し、署名を追加する。
    • send_transaction: 取引をブロックチェーンノードに送信する。

      DApps側のPythonプログラムでもラティス暗号を使用することで、ブロックチェーンのプログラムと一貫性が保たれる。この方法により、両方のシステムで同じ暗号方式を使用することができ、セキュリティと信頼性が向上する。
    • 4.ブロックチェーンノードのエンドポイント

      DAppsはこのデータをブロックチェーンノードに送信する。ブロックチェーンノードは取引データを受け取り、ブロックチェーンに記録する。

      ノードは以下の役割を果たす:

    • HTTPサーバーの設定

      • hyperクレートを使用してHTTPサーバーを構築し、tokioクレートを使って非同期で動作する。
    • 取引の受信と検証

      • receive_transaction関数は、HTTP POSTリクエストとして受信した取引データを処理する。
      • 取引データをデシリアライズしてTransaction構造体に変換し、署名の検証を行う。
      • 署名が正しければ、取引データをリストに追加し、成功メッセージを返す。署名が無効であれば、エラーメッセージを返す。
    • 署名の検証

      • ringクレートを使用して、取引データのハッシュと署名の検証を行う。
      • 署名の検証に成功した取引のみがリストに追加される。
    • 取引の受信:このRustコードは、DAppsプログラムとブロックチェーンプログラムの接続を実現するための重要な部分であり、以下の点で関連している。

      • DAppsプログラムは、ユーザーが作成した取引をHTTP POSTリクエストとしてブロックチェーンノードに送信する。このノードは、提供されたRustコードによって実装されている。
    • 署名の検証:提供されたRustコードではラティス暗号を用いた署名検証を実装する必要がある。

      • DAppsプログラムで生成された署名が正しいかどうかを、ブロックチェーンノードが検証する。これにより、取引の正当性とセキュリティが確保される。
    • 取引の記録

      • 検証に成功した取引は、ブロックチェーンノードによってブロックチェーンに記録される。この処理が成功した場合、ノードは成功メッセージを返す。
    • クレートの追加(Cargo.toml):
      [dependencies]
      serde = { version = "1.0", features = ["derive"] }
      serde_json = "1.0"
      tokio = { version = "1", features = ["full"] }
      rand = "0.8"
      sha2 = "0.10"
      hyper = "0.14"
       
    • 次に、以下にRustコードを示す。use hyper::service::{make_service_fn, service_fn};
      use hyper::{Body, Request, Response, Server, Method};
      use serde::{Deserialize, Serialize};
      use serde_json::json;
      use std::sync::{Arc, Mutex};
      use rand::Rng;
      use rand::distributions::Uniform;
      use sha2::{Sha256, Digest};

      #[derive(Serialize, Deserialize, Clone)]
      struct Transaction {
          sender_id: String,
          recipient_id: String,
          amount: f64,
          action_content: String,
          timestamp: String,
          signature: Vec<i32>,
      }

      type SharedTransactions = Arc<Mutex<Vec<Transaction>>>;

      const N: usize = 512;
      const Q: i32 = 1024;

      fn hash_message(message: &str) -> Vec<u8> {
          let mut hasher = Sha256::new();
          hasher.update(message);
          hasher.finalize().to_vec()
      }

      // 署名検証関数(ラティス暗号)
      fn verify_signature(public_key: &LatticePublicKey, message_hash: &Vec<u8>, signature: &Vec<i32>, q: i32) -> bool {
          let A = &public_key.A;
          let t = &public_key.t;
          let y = signature;
          let left_side: Vec<i32> = (0..A.len()).map(|i| (0..A.len()).map(|j| A[i][j] * y[j]).sum::<i32>()).collect();
          let right_side: Vec<i32> = (0..t.len()).map(|i| t[i] * message_hash[i] as i32).collect();
          left_side.iter().zip(right_side.iter()).all(|(&l, &r)| l % q == r % q)
      }

      #[derive(Clone)]
      struct LatticePublicKey {
          A: Vec<Vec<i32>>,
          t: Vec<i32>,
      }

      async fn receive_transaction(req: Request<Body>, transactions: SharedTransactions) -> Result<Response<Body>, hyper::Error> {
          match *req.method() {
              Method::POST => {
                  let whole_body = hyper::body::to_bytes(req.into_body()).await?;
                  let transaction: Transaction = match serde_json::from_slice(&whole_body) {
                      Ok(t) => t,
                      Err(_) => return Ok(Response::builder().status(400).body(Body::from("Invalid JSON")).unwrap()),
                  };

                  // 公開鍵の復元
                  let public_key = LatticePublicKey {
                      A: generate_random_matrix(N, Q), // 本来は公開鍵を受け取る必要があります
                      t: generate_random_vector(N, Q), // 本来は公開鍵を受け取る必要があります
                  };

                  // メッセージハッシュの計算
                  let transaction_data = transaction.clone();
                  let transaction_json = serde_json::to_string(&transaction_data).unwrap();
                  let transaction_hash = hash_message(&transaction_json);

                  if verify_signature(&public_key, &transaction_hash, &transaction.signature, Q) {
                      let mut transactions = transactions.lock().unwrap();
                      transactions.push(transaction);
                      Ok(Response::new(Body::from(json!({"status": "Transaction recorded"}).to_string())))
                  } else {
                      Ok(Response::builder().status(400).body(Body::from("Invalid signature")).unwrap())
                  }
              }
              _ => Ok(Response::builder().status(405).body(Body::from("Method not allowed")).unwrap()),
          }
      }

      #[tokio::main]
      async fn main() {
          let transactions = Arc::new(Mutex::new(Vec::new()));
          let transactions_clone = transactions.clone();

          let make_svc = make_service_fn(move |_| {
              let transactions = transactions_clone.clone();
              async move {
                  Ok::<_, hyper::Error>(service_fn(move |req| {
                      receive_transaction(req, transactions.clone())
                  }))
              }
          });

          let addr = ([127, 0, 0, 1], 5000).into();

          let server = Server::bind(&addr).serve(make_svc);

          println!("Server running on http://{}", addr);

          if let Err(e) = server.await {
              eprintln!("server error: {}", e);
          }
      }

      // ランダム行列生成関数
      fn generate_random_matrix(n: usize, q: i32) -> Vec<Vec<i32>> {
          let mut rng = rand::thread_rng();
          let between = Uniform::from(-q / 2..q / 2);
          (0..n).map(|_| (0..n).map(|_| rng.sample(&between)).collect()).collect()
      }

      // ランダムベクトル生成関数
      fn generate_random_vector(n: usize, q: i32) -> Vec<i32> {
          let mut rng = rand::thread_rng();
          let between = Uniform::from(-q / 2..q / 2);
          (0..n).map(|_| rng.sample(&between)).collect()
      }
       

      ・説明
    • 依存クレートのインポート:

      • hyper を用いてHTTPサーバーを構築し、serde と serde_json を用いてJSONデータを処理する。
      • serde と serde_json を用いてJSONデータをシリアライズおよびデシリアライズする。
      • rand と sha2 を用いてランダムな行列やベクトルの生成およびSHA-256ハッシュを計算する。
    • 構造体の定義:

      • Transaction 構造体を定義し、送信者、受信者、量、内容、タイムスタンプ、および署名を含む。
      • LatticePublicKey 構造体を定義し、ラティス暗号の公開鍵として行列 A とベクトル t を含む。
    • トランザクションリストの共有:

      • トランザクションリストを Arc<Mutex<Vec<Transaction>>> として共有する。
    • トランザクション受信関数:

      • receive_transaction 関数でPOSTリクエストを処理し、トランザクションデータを検証および記録する。
      • リクエストボディを受け取り、トランザクションデータをデシリアライズする。
      • トランザクションデータのハッシュを計算し、署名を検証する。
      • 署名が有効であればトランザクションをリストに追加し、成功レスポンスを返す。
    • 署名の検証:

      • 送信者IDから公開鍵を取得し、署名の検証を行う。
      • 公開鍵 A と t を用いて、トランザクションデータのハッシュと署名が一致するかを確認する。
    • サーバーの起動:

      • tokio::main 関数でサーバーを起動し、リクエストを待ち受ける。
      • make_service_fn と service_fn を用いてサービスを作成し、サーバーを構築する。
      • サーバーを指定されたアドレスで起動し、リクエストを処理する。

        このようにして、DApps側で取引データの署名生成と検証を行い、ブロックチェーンノードにデータを送信し、信頼性と透明性を確保することができる。
         
  8. ハッシュ値 (Hash Value)

    • 取引データ全体のハッシュ値。
    • 例: SHA-256アルゴリズムを用いたハッシュ値。

      取引データ全体のハッシュ値はプログラムの中で使用されている。具体的には、hash_message 関数を使用して取引データをハッシュ化している。以下は、プログラム内でのハッシュ値の生成と使用に関する部分を整理したものである。

    • ハッシュ関数の定義:
      fn hash_message(message: &str) -> Vec<u8> {
          let mut hasher = Sha256::new();
          hasher.update(message);
          hasher.finalize().to_vec()
      }

    • ハッシュ値の生成: トランザクションデータのハッシュ値を生成するために、hash_message 関数が使用される。取引データを文字列にシリアライズし、それをSHA-256アルゴリズムを用いてハッシュ化する。

    • ハッシュ値の使用: 生成されたハッシュ値は署名生成および署名検証に使用される。
       

  9. 取引ステータス (Transaction Status)

    • 取引が完了しているか、保留中か、取り消されているかなどのステータス情報。
    • 例: 「完了」「保留」「取り消し」。
  10. 取引のカテゴリ (Transaction Category)

    • 取引の種類やカテゴリ。
    • 例: 「地域貢献」「家庭支援」「環境保護」。
  11. 証拠データ (Proof Data)

    • 取引内容の証拠として提出される追加データ。
    • 例: 画像、動画、証明書。
  12. ジオロケーションデータ (Geolocation Data)

    • 取引が行われた場所の地理情報。
    • 例: 緯度と経度のデータ。
  13. 関連取引ID (Related Transaction ID)

    • 関連する他の取引のID。
    • 例: チェーン取引や複数段階の取引における関連ID。
  14. メタデータ (Metadata)

    • 取引に関連する追加情報。
    • 例: 取引の優先度、取引のコメント。
  15. ゼロ知識証明 (Zero-Knowledge Proof)

    • 取引の正当性を第三者に証明するためのゼロ知識証明データ。
    • 例: zk-SNARKsやzk-STARKsの証明データ。
  16. 関連アクションID (Related Action ID)

    • 取引に関連する愛の行動の識別情報。
    • 例: アクションID。
  17. 取引費用 (Transaction Fee)

    • 取引にかかる手数料。
    • 例: 愛貨の量。
  18. 承認者情報 (Approver Information)

    • 取引を承認した個人または組織の情報。
    • 例: ユーザーID、公開鍵。
  19. 愛の行動レベル (Love Action Level)

    • 取引に関連する愛の行動のレベル。
    • 例: レベル1~10。
  20. 受信日時 (Received Timestamp)

    • 取引が受信者によって確認された日時。
    • 例: ISO 8601形式で記録された日時。

これらの項目を包括的に管理することで、愛記システムの透明性と信頼性を確保し、すべての取引と愛の行動が正確かつ改ざんされていないことを保証できる。各項目について詳細な仕様を定義し、システム全体で統一的に管理することが重要である。

 

 

いかがであろうか、まだ項目の途中だが、次回に続きを記載したい。