Сбор агрегированных данных — одна из самых прибыльных отраслей в вычислительной технике, но как эффективно собирать данные, не нарушая конфиденциальность пользователей? Одним из ответов является многосторонний распределенный протокол агрегации (DAP), и метод PRIO3 — один из лучших в этой области.
Хотя безопасность применяется к данным в состоянии покоя и в процессе передачи, мы часто все еще выполняем вычисления с данными в виде открытого текста. Это создает множество проблем, особенно то, что процессор может определять PII (Персонально идентифицируемую информацию) и такие вещи, как секретные ключи шифрования. Один из подходов — использование MPC (Многосторонние вычисления), где мы можем разбить наши вычисления на более мелкие блоки и предоставить каждой из сторон долю вычислений. Одним из лучших применений этого является сбор статистики с учетом конфиденциальности.
Например, производитель мобильных телефонов может захотеть определить гендерный баланс владельцев своих телефонов, но при этом не раскрывать какую-либо конкретную личность. Для этого каждое клиентское устройство создает SNIP (секретно разделенное неинтерактивное доказательство) для своего пола. В PRIO3 это быстрое и эффективное доказательство с нулевым разглашением. Затем серверы могут получать эти SNIPs и проверять их на действительность. После проверки они могут обновить свои локальные аккумуляторы для текущей агрегации статистики. Затем, когда мы захотим раскрыть гендерный баланс с клиентских устройств, они смогут опубликовать свои общие итоги:
В целом, ни один из серверов не может определить, является ли клиент мужчиной или женщиной, поскольку создается доказательство с нулевым разглашением их пола; однако мы все еще можем вычислить итог. С PRIO3 ни один из серверов никогда не видит данные в виде открытого текста, и он основан на классической статье [here][1]:
Реализацию PRIO3 можно рассматривать как часть многостороннего распределенного протокола агрегации (DAP) для измерения конфиденциальности, который в настоящее время продвигается для стандартизации в IETF [here]:
Мы будем использовать PRIO3 для создания нескольких долей для логических значений (счетчик), а затем агрегировать данные обратно. Основной анализ — это базовый подсчет того, является ли что-то True или False, и набор данных — {true, false, 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).