PHP项目隐私集合求交PSI

wen PHP项目 3

PHP 项目隐私集合求交 (PSI) 实现方案

PSI(Private Set Intersection)允许双方在不泄露各自数据内容的情况下,找到集合的交集,以下是几种主流实现方案:

PHP项目隐私集合求交PSI

基于哈希和布隆过滤器(简单但非严格安全)

<?php
class SimplePSI {
    private $salt;
    public function __construct($salt = null) {
        $this->salt = $salt ?? bin2hex(random_bytes(16));
    }
    // 哈希并求交
    public function intersect($setA, $setB) {
        $hashedA = array_map([$this, 'hashItem'], $setA);
        $hashedB = array_map([$this, 'hashItem'], $setB);
        $intersection = array_intersect($hashedA, $hashedB);
        // 还原交集(需要双方都公开哈希值)
        return array_keys(array_intersect($hashedA, $hashedB));
    }
    private function hashItem($item) {
        return hash_hmac('sha256', $item, $this->salt);
    }
}
// 使用示例
$psi = new SimplePSI();
$setA = ['user1@email.com', 'user2@email.com', 'user3@email.com'];
$setB = ['user2@email.com', 'user4@email.com', 'user5@email.com'];
$common = $psi->intersect($setA, $setB);
print_r($common); // ['user2@email.com']

基于OPRF(Oblivious Pseudo-Random Function)

<?php
require 'vendor/autoload.php';
use Mdanter\Ecc\EccFactory;
use Mdanter\Ecc\Crypto\Key\PrivateKeyInterface;
class OPRFPSI {
    private $serverPrivateKey;
    private $generator;
    public function __construct() {
        $adapter = EccFactory::getAdapter();
        $this->generator = EccFactory::getSecgCurves()->generator256k1();
        $this->serverPrivateKey = $this->generator->createPrivateKey();
    }
    // 服务器端:接收盲化值并签名
    public function serverEvaluate(array $blindedValues): array {
        $results = [];
        foreach ($blindedValues as $blinded) {
            $point = $this->generator->getPublicKeyFrom($blinded['x'], $blinded['y']);
            $result = $point->mul($this->serverPrivateKey->getSecret());
            $results[] = [
                'x' => $result->getX(),
                'y' => $result->getY()
            ];
        }
        return $results;
    }
    // 客户端:盲化元素并计算
    public function clientEvaluate(array $data, array $serverResults): array {
        $hashes = [];
        foreach ($data as $i => $item) {
            // 去盲化
            $unblinded = $this->unblind($serverResults[$i], $this->clientRandomness[$i]);
            $hashes[] = hash('sha256', gmp_strval($unblinded->getX()) . $item);
        }
        return $hashes;
    }
}

基于OT(Oblivious Transfer)的实现

<?php
class OTBasedPSI {
    // 使用Naor-Pinkas OT协议
    public function otExtension(array $receiverInput, array $senderSet) {
        $commonElements = [];
        // 实现1-out-of-2 OT
        foreach ($receiverInput as $item) {
            $choiceBit = $this->hashToBit($item);
            // Bob(接收方)获得一个消息
            $received = $this->obliviousTransfer(
                $item,
                $choiceBit,
                $senderSet
            );
            if ($received === $item) {
                $commonElements[] = $item;
            }
        }
        return $commonElements;
    }
    private function hashToBit($item) {
        return hexdec(substr(hash('sha256', $item), 0, 1)) % 2;
    }
    private function obliviousTransfer($choice, $bit, $senderSet) {
        // 简化实现,实际应使用密码学安全协议
        return $senderSet[$bit] ?? null;
    }
}

使用PHP扩展 - libPSI包装

<?php
// 假设有一个C扩展包装了libPSI
class LibPSIWrapper {
    private $psiInstance;
    public function __construct(int $role) {
        // role: 0 = client, 1 = server
        $this->psiInstance = new PSI($role);
    }
    public function setup(int $numItems) {
        $this->psiInstance->setup($numItems);
    }
    public function addItems(array $items) {
        foreach ($items as $item) {
            $this->psiInstance->addItem($item);
        }
    }
    public function getIntersection(): array {
        $result = [];
        $this->psiInstance->computeIntersection(function($item) use (&$result) {
            $result[] = $item;
        });
        return $result;
    }
}

完整示例:Web API实现

<?php
// PSIEndpoint.php
class PSIEndpoint {
    private $redis;
    private $psiServer;
    public function __construct() {
        $this->redis = new Redis();
        $this->redis->connect('127.0.0.1', 6379);
        $this->psiServer = new SimplePSI();
    }
    public function handleRequest() {
        $action = $_POST['action'] ?? '';
        switch ($action) {
            case 'client_submit':
                return $this->clientSubmit();
            case 'server_submit':
                return $this->serverSubmit();
            case 'compute':
                return $this->computeIntersection();
            default:
                throw new Exception('Invalid action');
        }
    }
    private function clientSubmit() {
        $sessionId = bin2hex(random_bytes(16));
        $data = json_decode($_POST['data'], true);
        // 存储客户端数据(盲化后)
        $blindedData = array_map(function($item) {
            return hash('sha256', $item . $this->getSalt());
        }, $data);
        $this->redis->setex("psi:client:{$sessionId}", 3600, json_encode($blindedData));
        return json_encode(['session_id' => $sessionId]);
    }
    private function serverSubmit() {
        $sessionId = $_POST['session_id'];
        $data = json_decode($_POST['data'], true);
        $blindedData = array_map(function($item) {
            return hash('sha256', $item . $this->getSalt());
        }, $data);
        $this->redis->setex("psi:server:{$sessionId}", 3600, json_encode($blindedData));
        return json_encode(['status' => 'ok']);
    }
    private function computeIntersection() {
        $sessionId = $_POST['session_id'];
        $clientData = json_decode($this->redis->get("psi:client:{$sessionId}"), true);
        $serverData = json_decode($this->redis->get("psi:server:{$sessionId}"), true);
        $commonHashes = array_intersect($clientData, $serverData);
        return json_encode([
            'intersection_count' => count($commonHashes),
            'intersection_hashes' => array_values($commonHashes)
        ]);
    }
    private function getSalt() {
        return "YOUR_SECURE_SALT";
    }
}

性能优化与最佳实践

<?php
class OptimizedPSI {
    // 使用批量处理提高性能
    public function batchIntersect(array $clientSets, array $serverSet) {
        $results = [];
        // 1. 使用布隆过滤器预处理服务端数据
        $bloom = new BloomFilter(1024, 3); // 1024 bits, 3 hash functions
        foreach ($serverSet as $item) {
            $bloom->add($item);
        }
        // 2. 快速过滤客户端数据
        foreach ($clientSets as $clientId => $clientSet) {
            $candidates = [];
            foreach ($clientSet as $item) {
                if ($bloom->has($item)) {
                    $candidates[] = $item;
                }
            }
            // 3. 精确匹配
            $exactMatch = array_intersect($candidates, $serverSet);
            $results[$clientId] = $exactMatch;
        }
        return $results;
    }
    // 内存优化 - 处理大数据集
    public function streamIntersection($clientStream, $serverSet) {
        $hashedServer = array_map('sha256', $serverSet);
        $serverHashSet = array_flip($hashedServer);
        $intersection = [];
        foreach ($clientStream as $item) {
            $hash = hash('sha256', $item);
            if (isset($serverHashSet[$hash])) {
                $intersection[] = $item;
            }
        }
        return $intersection;
    }
}

安装与部署建议

  1. 生产环境要求

    • PHP 7.4+ 或 8.0+
    • OpenSSL 扩展
    • GMP 或 BCMath 扩展(用于大数运算)
    • 建议使用 PHP FFI 调用 C 库
  2. 性能考虑

    • 小数据集(<10k):使用哈希+布隆过滤器方案
    • 中等数据集(10k-100k):使用OPRF方案
    • 大数据集(>100k):使用OT扩展或专用C库
  3. 安全注意事项

    • 始终使用 HTTPS 传输
    • 使用安全的随机数生成器
    • 实施速率限制防止暴力攻击
    • 定期更换加密密钥

实现提供了不同安全级别和性能特征的PSI方案,你可以根据具体需求选择合适的实现,对于生产环境,建议使用经过审计的密码学库,如libPSI或emp-toolkit的PHP绑定。

抱歉,评论功能暂时关闭!