愛記システムの基本設計: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. 取引の正当性の確認

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

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

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

公開取引データについて

取引データを公開し、誰でも確認できるようにするというが、公開取引データの基本設計をするにあたり、いつ、何を、どのように設計していけばいいのか、具体的にプログラムも含めて見ていこう。公開取引データの基本設計を行うにあたり、以下のステップで進める。

  1. 公開取引データの定義

    • 公開すべき取引データの項目を定義する。例えば、取引ID、送信者、受信者、金額、タイムスタンプ、取引内容など。
    • プライバシーに配慮し、公開するデータから個人情報を排除する。
  2. データの公開方法

    • 取引データを公開するAPIエンドポイントを設計する。
    • 公開データを格納するデータベースまたはストレージを設計する。
  3. データの整合性と完全性の確保

    • 公開データの整合性チェックを実装する。
    • 公開データが改ざんされていないことを保証するための仕組みを設計する。
  4. 透明性の確保

    • 誰でも取引データを確認できるインターフェースを提供する。
    • 取引データの照会ログを記録し、誰がいつデータを照会したかを追跡できるようにする。

公開するデータから個人情報を排除する

以下に、DApps側であるPythonプログラムの設計における公開取引データの項目をすべて含めた具体的なプログラム例を示す。各項目について、公開時にはプライバシーに配慮し、必要な情報を匿名化または排除する。具体的に、どうやって匿名化しているのか、各項目毎に、理論的に説明していこう。
 

1. トランザクションID (transaction_id)

  • 匿名化方法: なし
  • 理由: トランザクションIDは一般的にランダムな文字列で生成され、個人を識別する情報を含まないため、匿名化の必要はない。

2. 送信者 (sender)

  • 匿名化方法: ウォレットアドレスの一部をマスク
  • 具体例: ウォレットアドレス 0x1234567890abcdef を 0x12****ef に変換
  • 理由: ウォレットアドレスが特定の個人を識別できるため、一部をマスクして個人が特定されないようにする。

3. 受信者 (receiver)

  • 匿名化方法: ウォレットアドレスの一部をマスク
  • 具体例: ウォレットアドレス 0xabcdef1234567890 を 0xab****90 に変換
  • 理由: ウォレットアドレスが特定の個人を識別できるため、一部をマスクして個人が特定されないようにする。

4. 金額 (amount)

  • 匿名化方法: なし
  • 理由: 金額自体は個人を特定する情報を含まないため、匿名化の必要はない。

5. 取引内容 (action_content)

  • 匿名化方法: 特定の個人を識別できる情報を削除
  • 具体例: 送信者: 太郎, 内容: サービス提供 → 内容: サービス提供
  • 理由: 取引内容に個人の名前や識別情報が含まれる場合、それを削除して個人が特定されないようにする。

6. 場所 (location)

  • 匿名化方法: 座標データをぼかす
  • 具体例: 緯度 35.6895 経度 139.6917 を 緯度 35.68 経度 139.69 に変換
  • 理由: 精密な位置情報は個人を特定する可能性があるため、精度を落としてぼかすことで個人の位置が特定されないようにする。

7. 市町村 (municipality)

  • 匿名化方法: なし
  • 理由: 市町村の情報自体は個人を特定する情報を含まないため、匿名化の必要はない。

8. タイムスタンプ (timestamp)

  • 匿名化方法: なし
  • 理由: タイムスタンプ自体は個人を特定する情報を含まないため、匿名化の必要はない。

9. 署名 (signature)

  • 匿名化方法: 署名情報をハッシュ化
  • 具体例: 署名: abcdef を ハッシュ化署名: e3b0c44298fc1c14...
  • 理由: 署名はデジタル署名であり、そのまま公開すると個人を特定する情報となるため、ハッシュ化して個人が特定されないようにする。

10. PoP(Proof of Place, proof_of_place)

  • 匿名化方法: 座標データをぼかす
  • 具体例: 緯度 35.6895 経度 139.6917 を 緯度 35.68 経度 139.69 に変換
  • 理由: 精密な位置情報は個人を特定する可能性があるため、精度を落としてぼかすことで個人の位置が特定されないようにする。

11. 承認者情報 (approver_info)

  • 匿名化方法: 公開鍵の一部をマスク
  • 具体例: 公開鍵 0x1234567890abcdef を 0x12****ef に変換
  • 理由: 公開鍵が特定の個人を識別できるため、一部をマスクして個人が特定されないようにする。

12. 取引の状態 (transaction_status)

  • 匿名化方法: なし
  • 理由: 取引の状態自体は個人を特定する情報を含まないため、匿名化の必要はない。

13. 手数料 (fee)

  • 匿名化方法: なし
  • 理由: 手数料自体は個人を特定する情報を含まないため、匿名化の必要はない。

14. 取引履歴 (transaction_history)

  • 匿名化方法: 特定の個人を識別できる情報を削除
  • 具体例: 送信者: 太郎, 受信者: 花子, 内容: サービス提供 → 内容: サービス提供
  • 理由: 取引履歴に個人の名前や識別情報が含まれる場合、それを削除して個人が特定されないようにする。

15. 公開ステータス (public_status)

  • 匿名化方法: なし
  • 理由: 公開ステータス自体は個人を特定する情報を含まないため、匿名化の必要はない。

16. 愛貨の種類 (currency_type)

  • 匿名化方法: なし
  • 理由: 愛貨の種類自体は個人を特定する情報を含まないため、匿名化の必要はない。

17. バリデーター情報 (validator_info)

  • 匿名化方法: 公開鍵の一部をマスク
  • 具体例: 公開鍵 0xabcdef1234567890 を 0xab****90 に変換
  • 理由: 公開鍵が特定の個人を識別できるため、一部をマスクして個人が特定されないようにする。

18. 手数料の割合表示 (fee_percentage)

  • 匿名化方法: なし
  • 理由: 手数料の割合表示自体は個人を特定する情報を含まないため、匿名化の必要はない。

19. 通知機能 (notification_status)

  • 匿名化方法: 通知内容から個人情報を削除
  • 具体例: 通知内容に含まれる名前や特定の情報を削除
  • 理由: 通知機能に個人の名前や識別情報が含まれる場合、それを削除して個人が特定されないようにする。

20. セキュリティ機能 (security_features)

  • 匿名化方法: 特定の個人を識別できる情報を削除
  • 具体例: セキュリティ機能に含まれる名前や特定の情報を削除
  • 理由: セキュリティ機能に個人の名前や識別情報が含まれる場合、それを削除して個人が特定されないようにする。

21. 送信者と受信者の情報 (sender_receiver_info)

  • 匿名化方法: ウォレットアドレスの一部をマスク
  • 具体例: 送信者 0x1234567890abcdef を 0x12****ef に、受信者 0xabcdef1234567890 を 0xab****90 に変換
  • 理由: ウォレットアドレスが特定の個人を識別できるため、一部をマスクして個人が特定されないようにする。

22. 愛貨のリスト表示 (currency_list)

  • 匿名化方法: なし
  • 理由: 愛貨のリスト表示自体は個人を特定する情報を含まないため、匿名化の必要はない。

23. 残高表示 (balance_display)

  • 匿名化方法: なし
  • 理由: 残高表示自体は個人を特定する情報を含まないため、匿名化の必要はない。

24. ユーザー検索機能 (user_search)

  • 匿名化方法: 検索結果から個人情報を削除
  • 具体例: 検索結果に含まれる名前や特定の情報を削除
  • 理由: ユーザー検索機能に個人の名前や識別情報が含まれる場合、それを削除して個人が特定されないようにする。

25. 友達リストの統合 (friends_list)

  • 匿名化方法: 特定の個人を識別できる情報を削除
  • 具体例: 友達リストに含まれる名前や特定の情報を削除
  • 理由: 友達リストに個人の名前や識別情報が含まれる場合、それを削除して個人が特定されないようにする。

26. QRコードスキャン機能 (qr_code_scan)

  • 匿名化方法: QRコードから個人情報を削除
  • 具体例: QRコードに含まれるアドレスや特定の情報を削除
  • 理由: QRコードに個人の名前や識別情報が含まれる場合、それを削除して個人が特定されないようにする。

27. 転送フォームのシンプル化 (transfer_form)

  • 匿名化方法: フォームから個人情報を削除
  • 具体例: フォームに含まれる名前や特定の情報を削除
  • 理由: 転送フォームに個人の名前や識別情報が含まれる場合、それを削除して個人が特定されないようにする。

28. 転送履歴の表示 (transfer_history)

  • 匿名化方法: 特定の個人を識別できる情報を削除
  • 具体例: 転送履歴に含まれる名前や特定の情報を削除
  • 理由: 転送履歴に個人の名前や識別情報が含まれる場合、それを削除して個人が特定されないようにする。

29. リアルタイムな価値情報 (real_time_value_info)

  • 匿名化方法: なし
  • 理由: リアルタイムな価値情報自体は個人を特定する情報を含まないため、匿名化の必要はない。

30. 価値チャートの統合 (value_chart)

  • 匿名化方法: なし
  • 理由: 価値チャートの統合自体は個人を特定する情報を含まないため、匿名化の必要はない。

31. 重要なイベントのアラート (event_alerts)

  • 匿名化方法: イベント内容から個人情報を削除
  • 具体例: イベント内容に含まれる名前や特定の情報を削除
  • 理由: 重要なイベントのアラートに個人の名前や識別情報が含まれる場合、それを削除して個人が特定されないようにする。

32. 手数料の変動通知 (fee_change_notification)

  • 匿名化方法: なし
  • 理由: 手数料の変動通知自体は個人を特定する情報を含まないため、匿名化の必要はない。

33. 手数料明細の提供 (fee_details)

  • 匿名化方法: なし
  • 理由: 手数料明細の提供自体は個人を特定する情報を含まないため、匿名化の必要はない。

34. 通貨換算の提供 (currency_conversion)

  • 匿名化方法: なし
  • 理由: 通貨換算の提供自体は個人を特定する情報を含まないため、匿名化の必要はない。

35. 受け取り先の確認 (recipient_verification)

  • 匿名化方法: 受け取り先アドレスの一部をマスク
  • 具体例: 受け取り先アドレス 0x1234567890abcdef を 0x12****ef に変換
  • 理由: 受け取り先アドレスが特定の個人を識別できるため、一部をマスクして個人が特定されないようにする。

36. ユーザーフィードバック (user_feedback)

  • 匿名化方法: フィードバック内容から個人情報を削除
  • 具体例: フィードバック内容に含まれる名前や特定の情報を削除
  • 理由: ユーザーフィードバックに個人の名前や識別情報が含まれる場合、それを削除して個人が特定されないようにする。

37. トランザクションIDの表示 (transaction_id_display)

  • 匿名化方法: なし
  • 理由: トランザクションIDは一般的にランダムな文字列で生成され、個人を識別する情報を含まないため、匿名化の必要はない。

38. 進捗バーの利用 (progress_bar)

  • 匿名化方法: なし
  • 理由: 進捗バー自体は個人を特定する情報を含まないため、匿名化の必要はない。

39. トランザクション履歴へのリンク (transaction_history_link)

  • 匿名化方法: リンク先から個人情報を削除
  • 具体例: リンク先のトランザクション履歴に含まれる名前や特定の情報を削除
  • 理由: トランザクション履歴へのリンクに個人の名前や識別情報が含まれる場合、それを削除して個人が特定されないようにする。

40. ユーザーサポート (user_support)

  • 匿名化方法: サポート内容から個人情報を削除
  • 具体例: サポート内容に含まれる名前や特定の情報を削除
  • 理由: ユーザーサポートに個人の名前や識別情報が含まれる場合、それを削除して個人が特定されないようにする。

このように、個人情報を含む可能性のある項目に対しては、適切な匿名化処理を施し、個人が特定されないように設計する。以下にプログラム例を示す。
import hashlib
import datetime
import re
from pymongo import MongoClient, errors
from flask import Flask, jsonify, request, abort

app = Flask(__name__)
client = MongoClient('mongodb://localhost:27017/')
db = client['blockchain_db']

# データ構造定義
class DataStructure:
    def __init__(self):
        self.transactions = db.transactions
        self.users = db.users
        self.approval_history = db.approval_history

data_structure = DataStructure()

# データの整合性要件
def validate_input_data(data):
    """ユーザー入力データのバリデーション"""
    if not re.match(r'^[a-zA-Z0-9]+$', data['transaction_id']):
        raise ValueError("Invalid Transaction ID")
    if not isinstance(data['amount'], (int, float)) or data['amount'] <= 0:
        raise ValueError("Invalid Amount")
    if not data['sender'] or not data['receiver']:
        raise ValueError("Sender and Receiver must be specified")
    if not data['timestamp']:
        raise ValueError("Timestamp must be specified")

# トランザクションの匿名化
def anonymize_transaction(transaction):
    """トランザクションデータを匿名化"""
    transaction['sender'] = mask_wallet_address(transaction['sender'])
    transaction['receiver'] = mask_wallet_address(transaction['receiver'])
    transaction['signature'] = hash_signature(transaction['signature'])
    if 'proof_of_place' in transaction:
        transaction['proof_of_place'] = mask_location(transaction['proof_of_place'])
    if 'approver_info' in transaction:
        transaction['approver_info']['public_key'] = mask_public_key(transaction['approver_info']['public_key'])
    if 'transaction_status' in transaction:
        transaction['transaction_status'] = transaction['transaction_status']
    if 'fee' in transaction:
        transaction['fee'] = transaction['fee']
    if 'transaction_history' in transaction:
        transaction['transaction_history'] = anonymize_transaction_history(transaction['transaction_history'])
    if 'public_status' in transaction:
        transaction['public_status'] = transaction['public_status']
    if 'currency_type' in transaction:
        transaction['currency_type'] = transaction['currency_type']
    if 'validator_info' in transaction:
        transaction['validator_info'] = mask_validator_info(transaction['validator_info'])
    if 'fee_percentage' in transaction:
        transaction['fee_percentage'] = transaction['fee_percentage']
    if 'notification_status' in transaction:
        transaction['notification_status'] = transaction['notification_status']
    if 'security_features' in transaction:
        transaction['security_features'] = transaction['security_features']
    if 'sender_receiver_info' in transaction:
        transaction['sender_receiver_info'] = anonymize_sender_receiver_info(transaction['sender_receiver_info'])
    if 'currency_list' in transaction:
        transaction['currency_list'] = transaction['currency_list']
    if 'balance_display' in transaction:
        transaction['balance_display'] = transaction['balance_display']
    if 'user_search' in transaction:
        transaction['user_search'] = anonymize_user_search(transaction['user_search'])
    if 'friends_list' in transaction:
        transaction['friends_list'] = anonymize_friends_list(transaction['friends_list'])
    if 'qr_code_scan' in transaction:
        transaction['qr_code_scan'] = mask_qr_code(transaction['qr_code_scan'])
    if 'transfer_form' in transaction:
        transaction['transfer_form'] = anonymize_transfer_form(transaction['transfer_form'])
    if 'transfer_history' in transaction:
        transaction['transfer_history'] = anonymize_transfer_history(transaction['transfer_history'])
    if 'real_time_value_info' in transaction:
        transaction['real_time_value_info'] = transaction['real_time_value_info']
    if 'value_chart' in transaction:
        transaction['value_chart'] = transaction['value_chart']
    if 'event_alerts' in transaction:
        transaction['event_alerts'] = anonymize_event_alerts(transaction['event_alerts'])
    if 'fee_change_notification' in transaction:
        transaction['fee_change_notification'] = transaction['fee_change_notification']
    if 'fee_details' in transaction:
        transaction['fee_details'] = transaction['fee_details']
    if 'currency_conversion' in transaction:
        transaction['currency_conversion'] = transaction['currency_conversion']
    if 'recipient_verification' in transaction:
        transaction['recipient_verification'] = mask_wallet_address(transaction['recipient_verification'])
    if 'user_feedback' in transaction:
        transaction['user_feedback'] = anonymize_user_feedback(transaction['user_feedback'])
    if 'transaction_id_display' in transaction:
        transaction['transaction_id_display'] = transaction['transaction_id_display']
    if 'progress_bar' in transaction:
        transaction['progress_bar'] = transaction['progress_bar']
    if 'transaction_history_link' in transaction:
        transaction['transaction_history_link'] = transaction['transaction_history_link']
    if 'user_support' in transaction:
        transaction['user_support'] = anonymize_user_support(transaction['user_support'])
    return transaction

def mask_wallet_address(address):
    """ウォレットアドレスの一部をマスク"""
    return address[:4] + '****' + address[-4:]

def hash_signature(signature):
    """署名をハッシュ化"""
    return hashlib.sha256(signature.encode()).hexdigest()

def mask_location(proof_of_place):
    """位置情報をぼかす"""
    proof_of_place['latitude'] = round(proof_of_place['latitude'], 2)
    proof_of_place['longitude'] = round(proof_of_place['longitude'], 2)
    return proof_of_place

def mask_public_key(public_key):
    """公開鍵の一部をマスク"""
    return public_key[:4] + '****' + public_key[-4:]

def anonymize_transaction_history(history):
    """トランザクション履歴を匿名化"""
    for transaction in history:
        transaction['sender'] = mask_wallet_address(transaction['sender'])
        transaction['receiver'] = mask_wallet_address(transaction['receiver'])
        transaction['signature'] = hash_signature(transaction['signature'])
    return history

def mask_validator_info(validator_info):
    """バリデーター情報をマスク"""
    validator_info['public_key'] = mask_public_key(validator_info['public_key'])
    return validator_info

def anonymize_sender_receiver_info(info):
    """送信者と受信者の情報を匿名化"""
    info['sender'] = mask_wallet_address(info['sender'])
    info['receiver'] = mask_wallet_address(info['receiver'])
    return info

def anonymize_user_search(search_results):
    """ユーザー検索結果を匿名化"""
    for result in search_results:
        result['user_id'] = mask_wallet_address(result['user_id'])
    return search_results

def anonymize_friends_list(friends):
    """友達リストを匿名化"""
    for friend in friends:
        friend['user_id'] = mask_wallet_address(friend['user_id'])
    return friends

def mask_qr_code(qr_code):
    """QRコードの一部をマスク"""
    return qr_code[:4] + '****' + qr_code[-4:]

def anonymize_transfer_form(transfer_form):
    """転送フォームを匿名化"""
    transfer_form['recipient_address'] = mask_wallet_address(transfer_form['recipient_address'])
    return transfer_form

def anonymize_transfer_history(transfer_history):
    """転送履歴を匿名化"""
    for transfer in transfer_history:
        transfer['sender'] = mask_wallet_address(transfer['sender'])
        transfer['receiver'] = mask_wallet_address(transfer['receiver'])
    return transfer_history

def anonymize_event_alerts(event_alerts):
    """イベントアラートを匿名化"""
    for alert in event_alerts:
        alert['event_id'] = mask_event_id(alert['event_id'])
    return event_alerts

def mask_event_id(event_id):
    """イベントIDの一部をマスク"""
    return event_id[:4] + '****' + event_id[-4:]

def anonymize_user_feedback(feedback):
    """ユーザーフィードバックを匿名化"""
    feedback['user_id'] = mask_wallet_address(feedback['user_id'])
    return feedback

def anonymize_user_support(support):
    """ユーザーサポートを匿名化"""
    support['user_id'] = mask_wallet_address(support['user_id'])
    return support

@app.route('/transactions', methods=['POST'])
def add_transaction():
    transaction = request.json
    try:
        validate_input_data(transaction)
        anonymized_transaction = anonymize_transaction(transaction)
        data_structure.transactions.insert_one(anonymized_transaction)
        return jsonify({'message': 'Transaction added successfully'}), 200
    except ValueError as e:
        return jsonify({'error': str(e)}), 400
    except errors.OperationFailure as e:
        return jsonify({'error': 'Database operation failed', 'details': str(e)}), 500

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=5000)

このプログラムは、DApps側での取引データを受信し、各項目ごとに匿名化処理を行った上でデータベースに保存するプロセスを示している。個人情報が含まれる項目はすべて匿名化され、システム内の公開取引データとして適切に処理される。

 

 

いかがであろうか、今回は公開取引データについて、プライバシーに配慮し、公開するデータから個人情報を排除する方法を記載した。考えられる項目は適切に排除しておく。現時点では上記のような設計としたい。