聚合数据的收集是计算领域最赚钱的行业之一,但是我们如何在不侵犯用户隐私的情况下有效地收集数据?嗯,多方分布式聚合协议 (DAP) 是一种答案,而 PRIO3 方法是目前最好的方法之一。
虽然安全性已应用于静态数据和空中传输的数据,但我们通常仍然对明文数据进行计算。这引发了很多问题,尤其是处理器可以确定 PII(个人身份信息)和诸如秘密加密密钥之类的信息。一种方法是使用 MPC(多方计算),我们可以将计算分解为更小的块,并让每个参与方共享计算。其中一个最好的应用是以隐私保护的方式收集统计信息。
例如,移动电话制造商可能想确定其电话所有者的性别比例,但实际上不透露任何特定的人。为此,每个客户端设备都会为其性别创建一个 SNIP(秘密共享的非交互式证明)。在 PRIO3 中,这是一个快速有效的零知识证明。然后,服务器可以接收这些 SNIP,并检查它们的有效性。检查完毕后,他们可以更新其本地累加器,以进行当前的统计信息聚合。然后,当我们想从客户端设备中揭示性别比例时,他们可以发布其聚合总数:
总的来说,没有一个服务器可以确定客户端是男性还是女性,因为创建了他们性别的零知识证明;但是,我们仍然可以计算总数。使用 PRIO3,没有一个服务器能够看到明文数据,并且基于经典论文 [here][1]:
PRIO3 的实现通常可以看作是用于隐私测量的多方分布式聚合协议 (DAP) 的一部分,该协议目前正在 IETF 中进行标准化 [here]:
我们将使用 PRIO3 为 Boolean 值(计数)创建多个共享,然后将数据聚合回来。核心分析是对某事物是 True 还是 False 进行基本计数,数据集为 {true, false, true, true},并将计算 true 值的数量 [here]:
package main
import (
"fmt"
"crypto/rand"
"os"
"io"
"strconv"
"github.com/cloudflare/circl/vdaf/prio3/count"
)
func fromReader[T any](r io.Reader) (z T) {
switch zz := any(&z).(type) {
case *count.Nonce:
_, _ = r.Read(zz[:])
case *count.VerifyKey:
_, _ = r.Read(zz[:])
}
return
}
var Context = []byte("Test")
func main() {
NumShares := uint8(2)
input := []bool{true,false,true, true}
argCount := len(os.Args[1:])
if argCount > 0 {
a,_ := strconv.Atoi(os.Args[1])
NumShares=uint8(a)
}
c, _ := count.New(NumShares, Context)
params := c.Params()
shares := params.Shares()
aggShares := make([]count.AggShare, shares)
for i := range aggShares {
aggShares[i] = c.AggregateInit()
}
for _, mi := range input {
nonce := fromReader[count.Nonce](rand.Reader)
verifyKey := fromReader[count.VerifyKey](rand.Reader)
randb := make([]byte, params.RandSize())
_, _ = io.ReadFull(rand.Reader, randb)
var pubShare count.PublicShare
var inputShares []count.InputShare
pubShare, inputShares, _ = c.Shard(mi, &nonce , randb)
var prepStates []*count.PrepState
var outboundPrepShares []count.PrepShare
for i := range shares {
state, share, _ := c.PrepInit(&verifyKey, &nonce, i, pubShare, inputShares[i])
prepStates = append(prepStates, state)
outboundPrepShares = append(outboundPrepShares, *share)
}
var prepMsg *count.PrepMessage
prepMsg, _ = c.PrepSharesToPrep(outboundPrepShares)
var outShare *count.OutShare
for i := range shares {
outShare,_ = c.PrepNext(prepStates[i], prepMsg)
c.AggregateUpdate(&aggShares[i], outShare)
}
}
numMeas := uint(len(input))
aggResult, _ := c.Unshard(aggShares, numMeas)
fmt.Printf("Inputs: %v\n\n", input)
fmt.Printf("Number of inputs: %d\n\n", numMeas)
fmt.Printf("Number of shares: %d\n\n", NumShares)
fmt.Printf("Aggregated Count %d\n\n", *aggResult)
for i := range shares {
fmt.Printf("Share %v\n", aggShares[i])
}
}
以及一个示例运行 [here]:
Inputs: [true false true true]
Number of inputs: 4
Number of shares: 4
Aggregated Count 3
Share {[[7227276485192055052]]}
Share {[[673113590378828220]]}
Share {[[14679250781088487564]]}
Share {[[14313847295054699691]]}
以下是求和示例:
PRIO3 for Verifiable Distributed Aggregation Functions for Summation with Go以及直方图:
PRIO3 for Verifiable Distributed Aggregation Functions for Histograms with Go[1] Corrigan-Gibbs, H., & Boneh, D. (2017). Prio: Private, robust, and scalable computation of aggregate statistics. In 14th USENIX symposium on networked systems design and implementation (NSDI 17) (pp. 259–282).