- MURRE
Mechanism for User Reports with Regulated Epsilon
The purpose of this document is to propose a new mechanism, MURRE, which can be used for machine learning applications while maintaining privacy in a differentially private way. Thus far, most other proposals have focused on how advertisers can receive aggregate reports on things like spend and performance. However, most machine learning infrastructure requires logs at a more granular level to operate correctly.
MURRE is not a full-blown proposal, but a starting point for discussion.
Stakeholder | Sentiment | Discussion |
---|---|---|
NextRoll | Interest | (this document) |
Through recent discussions in the W3C, we have thus far been primarily focused with the mechanisms that would enable ads to be displayed and bids to be produced. However, an open question for all such proposals thus far has been how optimization can occur with the current set of reporting proposals. MURRE attempts to answer this question with a relatively naive approach, but that is computationally feasible.
There are certain assumptions under which the MURRE proposal should be taken:
-
Machine learning algorithms in ad tech require granular data to function well.
-
Ad tech uses models of high dimension, with sparse vectors.
-
Differential privacy is a framework for understanding and protecting user privacy.
-
The user data collected by MURRE is not particularly sensitive. (We will discuss this at length below.)
-
Global differential privacy demands a trusted curator with access to data in the clear and has inherent limits on the number and type of queries that can be run. Therefore, we favor a local differential privacy mechanism.
-
Computation and network usage should be limited on the user agent. We don’t want to hammer a user’s CPU or ship a lot of data back and forth between a variety of servers. This practically demands a non-interactive local differential privacy, NLDP, mechanism.
-
More favorable mechanisms with better performance should preclude MURRE.
As noted in [5], there has been very little research into NLDP for even models such as linear regression. All current studies have produced negative results in the feasibility of this framework. This brings a tall order to the work at the W3C to bring strong privacy guarantees to end users, while also supporting the overall ad tech ecosystem, as revenue is largely supported by the efficacy of large machine learning models on ad tech data.
[1] demonstrates that for convex optimization in an LDP mechanism, the effective sample size of the collected data is , where is the privacy parameter and is the dimensionality of the problem. Given the high dimensionality of ad tech models, this implies that only a large will counteract the reduced accuracy of models. We reserve our justification of large for a later discussion, but we should keep this general result in mind.
[3] notes that interactive LDP mechanisms for convex optimization generally require as many back-and-forth rounds between the user and the central server as there are users in the protocol. Clearly, for ad tech this is not feasible. [3] explores how much this interactivity can be reduced, and proposes a few algorithms. Unfortunately, these algorithms depend on each user computing a binary tree with leaves, where is the number of samples, or that the user receive a current version of the model , which is likely to be in the gigabytes, to perform a gradient step. Neither of these is feasible for our use case.
[5] studies sparse NLDP in the convex case and proposes two algorithms. The first algorithm also demands sending to every user and is thus infeasible. The second algorithm only protects the labels in the dataset, but for ad tech, the browsing behavior is the sensitive part we want to keep private, probably much moreso than the labels, so this is also a non-starter.
[4] revisits the problem in [5] and proposes a new algorithm for high dimensional cases. It requires a dimensional reduction to , and the server randomly generates a sub-Gaussian matrix of dimension . The seed can be sent to each user, but then the user must compute this same matrix to transform their private data. For the sizes of that we’re talking about, where a vector is in the gigabytes, it is not feasible for each user to generate an matrix and perform computations with it.
[6] has a set of algorithms that are not feasible for our use case, as they hinge on each user applying a vector of Gaussian noise to their private vector and sending it back to the server. This is a no-go because the vector needs to be the size of the model, so each user would be sending gigabytes over the wire. Sparsity likely needs to be maintained through the network.
Apparently, there is very little in the literature to help us find a differentially private way of receiving granular data from users.
As stated previously, MURRE is a naive algorithm that is designed to be computationally feasible at the expense of a large . This is a starting point for discussion, with the hope that at least some concreteness in a proposal to achieve an optimization mechanism spurs further creativity.
This section is entirely lifted from [2], page 29. Consider a survey that asks a “yes/no” question where the response is embarrassing or incriminating. Responders are asked to first flip a coin: if it comes up heads, they answer truthfully; if it comes up tails, they flip again, and if it comes up heads, they answer “yes”, otherwise “no.” This is a differentially private mechanism:
This gives respondents a plausible deniability: their answer could have been the result of random chance, but the analyst can use knowledge of the mechanism to determine roughly what the true proportion of “yes” responses should have been.
Of course, we can generalize this such that the first flip is a Bernoulli trial with probability , and the second flip, if needed, is still fair. We would then have:
This, of course, matches our intuition. If , where the respondents never answer truthfully, then (undifferentiated random response), and if , then (no privacy).
Suppose that a user has a feature vector . We can perform the same operation as above over every dimension of . For ease of analyis, we assume that every dimension is independent. We would then have:
And so scales linearly with , which is unsurprising given that this is a composition of a -differentially private mechanism times. However, with large , it would be computationally infeasible to run this many Bernoulli trials in the browser. We can rapidly compute the mechanism by drawing a couple binomial variates. For large these are also difficult to draw, but we can use a normal approximation. That is, the indices that would need to have their bits flipped can be represented as:
Here, represents how many of the dimensions we would have to flip the fair coin for, and represents how many of those dimensions we would have to flip bits on. Letting , we would have that:
This process results in a private vector which can be communicated to an advertiser for machine learning purposes. Pseudocode will be presented later.
In ad tech practice, it would not be feasible in the browser to construct an of dimension purely from the categorical features, as it would require constructing a large map, e.g. mapping all domains or URLs to a space of integers. To get around this, the hashing trick can be employed. The hash function where compresses the space as it accepts collision.
We somewhat abuse differential privacy here, as is not a random mechanism, but in practice, it can be treated as such. Rather than:
where the supremum is taken over all and . We suggest:
The numerator is 1 because is deterministic, and the denominator assumes a well-distributed hash where an arbitrary can expect to be mapped to a particular with a probability of . Despite the abuse, this makes intuitive sense: for , where everything gets mapped to a single value, results in a 0-differentially private mechanism as all the original data is destroyed. Things break down a bit when considering the space of hash functions where , as a perfect hash would be -differentially private instead of -differentially private (no other could result in ). But for practical purposes, we believe this interpretation is suitable.
Now our mechanism is to first perform the hashing trick and then create the randomized response on the hashed space.
And, sure enough, the s add. However, critically, the random response mechanism is now over dimension instead of . As a sanity check, note that if , then this expression reduces to , which is exactly the same privacy as in the single random response case, which is what we would expect as .
This is perhaps the most crucial problem to solve. In a very real sense, the way the ad tech industry operates today is with and , which offers no privacy at all under the definition of local differential privacy. This means that any and/or any is an improvement over the current state of the art as far as privacy is concerned.
Yet the accuracy of ad tech models are crucial to the economics of the open web today. When research ([1]) thus far indicates a sample degradation of for convex optimization in NLDP, in order to prop up accuracy, must be large to counteract the typical high dimensions of . We have no theoretical analysis of achieving a desired accuracy in MURRE with respect to any of the configurable parameters (though given its simplicity empirical results are very plausible to construct). But regardless of this, all signs point to a large .
But is this really that much of an issue? To quote from [2], page 25:
But what of large values for ? Failure to be -differentially private merely says there exist neighboring databases and an output for which the ratio of probabilities of observing conditioned on the database being, respectively, or , is large. An output of might be very unlikely (this is addressed by -differential privacy); databases and might be terribly contrived and unlikely to occur in the “real world”; the adversary may not have the right auxiliary information to recognize that a revealing output has occurred; or may not know enough about the database(s) to determine the value of their symmetric difference. Thus, much as a weak cryptosystem may leak anything from only the least significant bit of a message to the complete decryption key, the failure to be - or -differentially private may range from effectively meaningless privacy breaches to complete revelation of the entire database. A large epsilon is large after its own fashion.
So, as an industry, we should consider how much privacy is actually being leaked by having a large .
Let’s consider the MURRE mechanism specifically. The original data is hashed by the browser (to be described below as we get into the technical aspects of the proposal). That vector is then noised, likely with a high to maintain sparsity, which means most dimensions that were originally set to 1 will not be flipped to a 0. But the DSP receives this vector with no ties to an individual user identifier.
In principle, the DSP could choose a publisher’s URL to hash and choose an advertiser’s URL to hash, which would tell them the dimensions to look for 1 in their noised dataset, which could then be interpreted as saying at some point a visitor to the advertiser’s site also visited this publisher’s site. But those dimensions could also be set to 1 because of a hash collision, and then additionally, could have also been set to 1 by the random response. This is the plausible deniability, but is it plausible enough? For our part, we say yes.
Performing this at scale to be privacy-violating is exceedingly unlikely. It’s simply too many things to hash and search for in the dataset to make any detailed claims about user browsing behavior. And, as stated, there are no user identifiers available directly in the dataset. If a DSP attempts to use user identifiers as part of their original feature set, that will only increase the number of collisions in the hash space, further increasing plausible deniability.
Finally, we should keep in mind that differential privacy treats the 0s just as valuably as the 1s, which inflates . In a strict mathematical sense, this is completely justifiable. For the application to ad tech, though, the 0s are not particularly privacy-violating. Remember that is sparse, so there are many, many 0s in a given vector. We claim that not taking an action is not embarrassing. Even if it were, with the way ad tech functions, the answer to a query such as “didn’t visit website ” would be encoded as a 1 in some dimension. That is to say, under the definition of differential privacy, a large epsilon should be expected. As in the quote, “A large epsilon is large after its own fashion.”
So why all the analysis above if we don’t intend to hem and haw about ? We care because it provides a benchmark to compare different solutions. If another mechanism is proposed counter to MURRE that has the following properties:
-
Is an NLDP mechanism so we’re comparing apples to apples
-
Is computationally feasible
-
Is acceptable to the broader industry
then such a proposal should displace MURRE. The combination of and provides a benchmark to evaluate competing proposals.
We do not recommend selecting an directly, but rather having it defined through a selection of both and based on technical and accuracy concerns. While we don’t have a theoretical analysis of how these parameters affect model performance, we can provide an empirical analysis.
The choice of has very little to do with the technical side of things. We would hope that . For privacy reasons, it’s good to have be as small as possible without any significant impact on accuracy.
So we ran some tests. We chose a baseline performance where , and we ran models by powers of two all the way down to . These were run over a CTR dataset with two types of logistic models: one that is purely linear, and one second-order model that employs Factorization Machines (FM). FM picks up interaction between terms, and we see that it’s more robust to hash collisions than the purely linear model. We looked at three metrics: AUC-ROC, AUC-PR (precision-recall), and log-loss:
Relative AUC-ROC as a function of M Relative AUC-PR as a function of M Relative log-loss as a function of Mis quite different. A very small , though very private, will begin to densify . This will drastically increase the amount of data we have to send over the wire under a resonably sized . Thus, should have a lower bound to ensure the feasibility of the proposal. From there, we also need to be large enough to not have a detrimental impact on accuracy.
For these reasons, we ran experiments with ranging from for with a fixed . These values are all very close to 1, which means we’re asking the browser to tell the truth very often, but note the amount of ones we’re actually adding to the vector, on average:
This is a completely reasonable size to send over the wire, a mere 256 additional integers to send. From a data interpretation perspective, this could be 256 different domains the user visited, 256 different advertisers, or campaigns, or ads, or any combination of these. We believe that this adds quite a bit of plausible deniability to the user’s data. Here’s what we see:
Relative AUC-ROC as a function of p Relative AUC-PR as a function of p Relative log-loss as a function of pNote that we didn’t change our hyperparameters at all from what we do today, so maybe performance can be eked out beyond what we see here, but we didn’t want to fiddle with too many variables at once. The purely linear model fares quite well, whereas the FM model suffers a steep dropoff. We have some theories around this, but these are beyond the scope of this document.
MURRE certainly has weaknesses, but we think it’s a good starting point for discussion. Here are a few that come to mind readily:
-
MURRE only supports binary vectors. While continuous values can be binned to become categorical, perhaps this is too restrictive. Maybe MURRE can be extended to support continuous values natively, but the concern here would be destroying the sparsity of the vector as the 0s would have to undergo continuous noising as well. It also drastically complicates the analysis.
-
MURRE assumes independence in all dimensions. Of course, some dimensions will be highly, if not perfectly, correlated, e.g. a particular ad is always attached to the same advertiser. Lacking independence will increase , but these dependent relationships will vary by DSP and would have ground the analysis to a halt.
-
MURRE also treats all s as equally probable, when in reality more common vectors benefit from greater privacy than very unique ones. Once again, the distribution on these datasets will vary by DSP, and so to make any progress, we made this assumption.
In this section, we discuss the interfaces and dataflows that would actually make MURRE function. As a quick overview, there are a few key mechanisms:
-
The browser collects a list of events for each DSP.
-
The DSP provides a feature extraction function.
-
This same feature extraction function is also capable of producing labels.
-
On certain events, like impressions, clicks, and conversions, the browser evaluates this function to produce the set of features.
-
The browser hashes each element of this set with a publicly known hash function.
-
The browser carries out the random response mechanism.
-
The browser encrypts the vector with the DSP’s public key.
-
The browser sends the encrypted payload to a proxy server.
-
The proxy server forwards the payload to the DSP for decryption and logging.
After this, we will also discuss how models can be derived and deployed to operate in mechanisms where advertiser and publisher/contextual data are uncorrelated, such as TURTLEDOVE, TERN, SPARROW, and Dovekey.
To create any useful vectors for machine learning, first a “trail” must be created that captures the sequence of events the browser has experienced. Later, a vector will be computed from this trail, but first we describe how it’s constructed.
The browser starts with an empty list trail = []
that is namespaced by
the DSP. The browser then visit’s an advertiser’s page, where the DSP’s
pixel writes interest groups into the browser. This becomes an event
that gets pushed into trail
:
trail.push({ 'advertiser': 'https://advertiser.example',
'timestamp': 1604013974,
'type': 'pixel',
'event_id': 'random_string_31287',
'data': { 'groups': ['group1', 'group2'],
'products': ['product1'],
... // all sorts of other data }
})
The ’event_id’
is a random string generated by the browser and it will
never leave the browser. It will become important later for identifying
trigger events. Later, the browser is served an impression for this
advertiser. Only the browser knows this, and it pushes another object
into trail
:
trail.push({ 'advertiser': 'https://advertiser.example',
'timestamp': 1604014974,
'type': 'impression',
'event_id': 'random_string_123989',
'data': { 'ad-name': 'ad12345',
'ad-size': '1024x768',
'url': 'https://publisher.example/path/to/page.html',
... // all sorts of other data }
})
The user clicks the ad, which creates another event:
trail.push({ 'advertiser': 'https://advertiser.example',
'timestamp': 1604015000,
'type': 'click',
'event_id': 'random_string_9812387',
'data': { 'ad-name': 'ad12345',
'ad-size': '1024x768',
'url': 'https://publisher.example/path/to/page.html',
... // all sorts of other data }
})
And finally, the user converts on the advertiser’s site. This is another
pixel
-type event, but the DSP is explicit about this, and instead we
push:
trail.push({ 'advertiser': 'https://advertiser.example',
'timestamp': 1604018102,
'type': 'conversion',
'event_id': 'random_string_78123',
'data': { 'products': ['product2', 'product5'],
'conversion-value': 'USD$100',
... // all sorts of other data }
})
At this point, we would have:
trail = [{ 'advertiser': 'https://advertiser.example',
'timestamp': 1604018102,
'type': 'conversion',
'event_id': 'random_string_78123',
'data': { 'products': ['product2', 'product5'],
'conversion-value': '1024x768',
... // all sorts of other data }
},
{ 'advertiser': 'https://advertiser.example',
'timestamp': 1604015000,
'type': 'click',
'event_id': 'random_string_9812387',
'data': { 'ad-name': 'ad12345',
'ad-size': '1024x768',
'url': 'https://publisher.example/path/to/page.html',
... // all sorts of other data }
},
{ 'advertiser': 'https://advertiser.example',
'timestamp': 1604014974,
'type': 'impression',
'event_id': 'random_string_123989',
'data': { 'ad-name': 'ad12345',
'ad-size': '1024x768',
'url': 'https://publisher.example/path/to/page.html',
... // all sorts of other data }
},
{ 'advertiser': 'https://advertiser.example',
'timestamp': 1604013974,
'type': 'pixel',
'event_id': 'random_string_31287',
'data': { 'groups': ['group1', 'group2'],
'products': ['product1'],
... // all sorts of other data }
}]
Recall that this list is namespaced by the DSP, not the advertiser. There can be lots of advertisers mixed in this list, but we will address this in the next section. Of course there can be multiple impressions, multiple clicks, and so on.
Multiple pixel events in a row can be special, though. DSPs generally
just care about the complete state of a user before labeling an “event
of interest.” This full state can be communicated by the DSP in the
’data’
object of pixel events, which means that we can perform an
update-in-place for any pixel events that come after the most recent
even of interest. In code:
inserted = False
if event.type == 'pixel':
i = 0
while i < length(trail):
if trail[i].advertiser == event.advertiser:
if trail[i].type == 'pixel':
trail[i] = event
inserted = True
break
else:
trail.push(event)
inserted = True
break
i += 1
if not inserted:
trail.push(event)
This is just a quick idea for storage optimization; perhaps it’s easier to just use a fully granular list. We have no strong opinions on this.
We also note that the data to construct the pixel and conversion events
can be extracted from the writeAdvertisementData()
as proposed in
TERN. This
makes MURRE particularly synergistic with TERN, but MURRE is applicable
to the other proposals as well.
Though a full discussion of this is beyond the scope of this document, we believe that these trails can also be leveraged for other use cases. Things that immediately come to mind:
-
They could be used to generate reports for any future reporting APIs.
-
They can be used to implement arbitrary attribution mechanisms.
-
A UI could be layered over them to give users better insights into their data, potentially even broken down by individual advertiser.
-
Control mechanisms could be provided to the user for them to remove data they feel is personally sensitive: viewing certain products, visiting particular websites, etc.
The DSP provides an endpoint for the browser to call,
https://dsp.example/.well-known/extraction
. This endpoint is
responsible for returning a JSON object containing a few necessary
pieces of information:
{
'dsp-public-key': '2akdfj0wkadfjaksdjf',
'feature-dimension': M,
'label-dimension': L,
'extraction-function-url': 'https://dsp.example/js/extraction.js'
}
The public key is used for encryption and the feature dimension is the same as above. We also introduce a new dimension for labels, which we will discuss in this section. The extraction function will be the bulk of what we describe here.
The extraction function is where a lot of the DSP’s “special sauce” is contained. When a trigger event occurs in the browser for a given advertiser, the browser constructs:
advertiser_trail = [event for event in trail if event.advertiser == trigger_event.advertiser]
That is, the browser creates a sub-list of the full trail that only has to do with the advertiser in question. This ensures that user data stays siloed by advertiser for privacy reasons. From here, the browser invokes:
vector = extractor(advertiser_trail, event_id) {
// all sorts of logic here
}
This function returns this JSON vector
object of the form:
{
'features': ['some_string_1', 'some_string_2', ..., 'some_string_t'],
'labels': [1, 4]
}
This is all very abstract (with reason), so let’s look at a basic
working example. We may have a simple extractor()
function like:
function extractor(trail, event_id) {
features = []
labels = []
advertiser = trail[0].advertiser
impressions = 0
page_visits = 0
for event in trail:
if event.type == 'click':
labels.push(1)
continue
// ... maybe some other types of labels
if event.type == 'conversion':
labels.push(7)
continue
if event.type == 'impression':
impressions += 1
continue
if event.type == 'pixel':
page_visits += 1
continue
features.push('{}:{}:{}'.format(advertiser, 'imps', impressions))
features.push('{}:{}:{}'.format(advertiser, 'pvs', page_visits))
return { 'features': features, 'labels': labels }
}
(We’re not using the event_id
here; we’ll cover this later when we
talk about trigger events.) Say we’re talking about a trail where the
browser saw 12 impressions from this advertiser after 3 page visits, and
the user clicked. Then the output would be:
{
'features': ['https://advertiser.example:imps:12',
'https://advertiser.example:pvs:3'],
'labels': [1]
}
For the ’features’
list, we’re encoding very clearly some of the user
browsing behavior related to this advertiser that the user has engaged
in. For the ’labels’
list, the DSP has chosen to assign dimension 1 to
indicating that a click has occurred, and expresses that here because
the user did indeed click. If the user took no positive action, this
would be an empty list.
The labeling mechanism allows some flexibility for DSPs to select the
types of models they want to build. However, the dimension
expresses just how many
types of labels the DSP intends to construct. This ’labels’
list is
going to be sent in the clear, so
cannot be too large. We
leave this open to discussion on what an appropriate value for
is. However, if for
some reason, the extractor function returns an integer larger than
, the browser can check
this and invalidate the whole computation so the DSP gets nothing.
As for the features, these can appear privacy-invasive at first blush, but that will soon change. Nothing has left the browser at this point.
Let us now talk about trigger events. As previously stated, DSPs are largely concerned about the immediately prior feature set of the browser before an event of interest occurs. Some very obvious trigger events that are useful before a label:
-
Impressions: This entire extraction routine should be triggered by any impression event. It does not need to be triggered immediately, as, for example, whether to label a vector as having triggered a click will take some time for the user to click. The important thing is that the browser remember when and for which advertiser an impression event occurred and to compute the vector some reasonable, but random (to prevent timing attacks), time later. Just to throw a number out there, say we allow 2 hours for a user to click on an ad. Thus, on an impression event, the browser records
(timestamp, advertiser, event_id)
. Associated with this tuple, the browser generates a reporting time . Once this reporting time is reached, the browser computesadvertiser_trail
and kicks off the rest of the extraction process, passing in theevent_id
.Note that this gives the DSP an opportunity in the extraction function to label the impression as either having been positively or negatively labeled. Since more impressions could have been served in between this trigger event and the reporting time, the
event_id
can be used by the extractor to identify specifically which impression should have its features extracted (like the publisher site, ad slot, etc.). The extractor can look forward from this event to decide if the impression was clicked or not. -
Conversions: Conversions are another major event that should trigger the extraction process. Just like with impressions, this should be subject to a delay in extraction along with passing in the relevant
event_id
. Note that with the extractor function having access to the full trail, this allows DSPs to use whatever attribution mechanism(s) they wish for their labeling output. This level of flexibility is why we’re supportive of the browser maintaining the trail and allowing DSPs to specify their extractor functions as they see fit.
We exclude some event types from triggering a report:
-
Clicks: We have already described a mechanism under which impressions can be identified as having been clicked, so this would be duplicative.
-
Pixels: The DSP already has access to all data here as it happens in a first-party context, as so there is no need to report anything.
There are likely many other types of events we would want to consider and how they fit into the MURRE framework. Once again, this is a starting point for discussion, and modifications can be made in the future after further discussion.
Given the vector
object, it’s time for the browser to execute the
MURRE NLDP mechanism. Using an appropriate hash function hash
that has
range , we
have the browser do:
hashed_features = set([hash(feature) for feature in vector.features])
That’s it and it’s very straightforward. Note that the choice of hash function must be standardized across browsers and known to the DSP for inference later. It does not need to be cryptographically secure hash function, so it can be computed quickly, and it should have good uniformity properties. As an aside, we would recommend either MurmurHash3 or xxHash. It’s easiest to just pull the first bits of the hash, and this would constrain for some .
Anyway, now that the feature hashing is performed, we need to do the random response mechanism. Once again, this is very straightforward:
h = random.normal(M*(1 - p), M*p*(1 - p))
k = int(random.normal(h / 2, h / 4))
S = set()
for _ in range(k):
S.add(int(M * random.uniform()))
z = set()
z.add(hashed_features)
z.add(S)
z.remove(hashed_features.intersect(S))
And now the browser has computed in a sparse format.
We will be using a proxy server to which the browser will report its vector. This ensures that the browser doesn’t communicate with the DSP along with its vector, so the DSP cannot associate the two. We propose a simple mechanism to try to avoid fraudulent vectors making their way into the DSP’s dataset and defenses against replay attacks; this is just an example and can be replaced by some other trust mechanism, and it is not the main thrust of the MURRE proposal overall.
Prior to everything, the DSP generates dsp_secret_validation_key
(this
is not the private key for the encryption mechanism, but separate). This
secret key is shared with the proxy.
At some point, the browser generates a random_seed
and queries
https://dsp.example/.well-known/proxy-validation
with this seed, and
the DSP responds back with:
{
'signed-seed': secure_hash(random_seed, dsp_secret_validation_key, date),
'date': date
}
The DSP, at this point, can refuse to perform the signing, for example if the request is coming from a suspicious IP address, or the browser hasn’t been validated through the Trust Token API. The DSP is free to set its own policy here.
The browser now creates a new object:
private_vector = { 'features': list(z),
'labels': vector.labels }
The browser encrypts this with the DSP’s public key and puts the result into a new object:
payload = { 'dsp': 'https://dsp.example',
'seed': random_seed,
'signed-seed': signed_seed,
'date': date,
'data': encrypt(private_vector, dsp_public_key) }
The browser POSTs payload
to https://proxy.example/reporting
.
Reading this payload, the proxy computes:
secure_hash(random_seed, dsp_secret_validation_key, date)
to confirm that the DSP did, indeed, sign off on wanting to receive data from this browser on the date claimed. If the date is too old, the proxy rejects the request. This is designed to prevent replay attacks in the long-term.
The proxy, using a previously generated proxy_secret_key
computes:
id = secure_hash(signed_seed, proxy_secret_key)
The proxy then sends the DSP:
{
'id': id,
'data': data
}
From here, the DSP can decrypt the data and add it to their dataset. This schema has a few valuable properties:
-
The DSP can reject untrustworthy browsers under their own policy.
-
The proxy is unable to read the DSP’s vector data.
-
The DSP is not able to attach any user identifier to the vector data.
-
The proxy rejects any requests where the date is too old preventing long-term replay attacks.
-
The DSP can maintain a cache of the
id
s coming from the proxy server to check for duplicates, preventing short-term replay attacks. -
The proxy is pretty close to a dumb pipe; it doesn’t need to store any data. This is simpler than maintaining a trusted curator under a global differential privacy model.
This completes the MURRE mechanism.
Ok, so we have a mechanism for the DSP to receive an anonymized, noisy training set over which to compute machine learning models. For clarity, let’s discuss how inference happens. We assume a generalized linear model, where our predictions are . Here, is the learned model that has been trained over the dataset.
Either while on the advertiser’s site (such as in TERN) or during the
fetch-ads
request (as in TERN and TURTLEDOVE), the DSP has access to
user data, but no contextual data. TERN specifies this mechanism more
fully, so we will assume TERN from here.
At pixel time and during the selection of ads, the DSP, server-side runs
the same logic over the user data as is present in extractor()
to
derive its user features, and then computes the hash()
of these
features. These can be strings representing interest groups, number of
page visits, products viewed, etc. Since the hash functions are the
same, the DSP now has a subset of the dimensions where
is set to 1; call it
.
We can compute
.
is a partial
sum, and it can be sent to the browser in writeAdvertisementData()
in
the privateData
object. This ensures that it will eventually make it
into the generate_bid()
function.
Also available for sending in the privateData
object are frequency
adjustments. The DSP can compute something like
hash(’https://advertiser.example:imps:10-20’)
which provides the
dimension where
is the
contribution. Doing this for all frequency bins, the DSP can construct
an object:
freq_bins = {
'frequency-1-5': w[237648],
'frequency-6-10': w[62384759],
'frequency-10-20': w[5172638]
}
(Note that these are frequency bin weights specifically for this
advertiser, and will be part of an adSignals
object that is also
directly attached to this same advertiser.)
Later, the browser is on a publisher page. The DSP receives a contextual
request from the SSP. Here, the story is much the same. All the features
that the DSP has for the data in the contextual request can be
represented as strings and hashed into a vector
which is just another subset of the actual vector
.
The DSP computes
to compute another partial sum and sends this back to the browser
through the publisherSignals
object, which will also get passed to the
generate_bid()
function.
TERN asks that the browser compute some metrics before executing the
generate_bid()
function into a browserSignals
object. One such
example was the frequency of ads shown to the user. Of course, this also
gets passed into the generate_bid()
function.
Here is some example logic for this generate_bid()
function:
function generate_bid(adSignals, publisherSignals, browserSignals) {
function f(input) {
// whatever f is
}
y_a = adSignals.privateData.y_a
y_b = publisherSignals.y_b
freq = browserSignals.frequency
function bin_frequency(freq) {
// logic to bin the frequency into the same bins as are
// in adSignals.privateData
}
freq_weight = adSignals.privateData.freq_bins[bin_frequency(freq)]
sum = y_a + y_b + freq_weight // equal to dot(w, x)
return f(sum)
}
In short, we see how MURRE and TERN work together to permit the evaluation of full machine learning models using user data, contextual data, and browser data while keeping the actual models private on the DSP server side.
SPARROW relies on a trusted third-party server that runs model evaluations. It receives in the clear, so the primary concern for the DSP is to ship some logic to this third-party server that knows how to execute directly.
Dovekey operates on the notion that the machine learning model can be “materialized.” It would be incumbent on the DSP to synthetically construct a variety of vectors on their own and then compute for every vector they generate. Essentially, Dovekey is a giant hashmap where the DSP enters each as a key (likely represented as the raw set of strings without hashing) and as the value. Dovekey, like SPARROW, relies on a trusted third-party server that has this hashmap, and it would receive in the clear (once again, as a string representation) to perform the lookup.
Alternatives that are in the same class as MURRE were covered in the Related Work and rejected due to infeasibility.
Then there are a set of alternatives we would consider to be in separate classes from MURRE. Some of these are not designed to perform machine learning optimization. Others use aggregate reporting, which is not how machine learning models typically function, and it is still an open question on how to leverage such aggregates for this purpose. MURRE really isn’t designed to be a reporting mechanism, but a training dataset generation mechanism.
The Conversion Measurement API (CMAPI) is primarily an attribution mechanism than a means to provide machine learning data. It is currently being fixed to a last-click attribution model. There is a proposed mechanism to allow for arbitrary attribution models, but this requires aggregate reporting, which, as stated above, is not how machine learning models typically function MURRE allows the DSP to optimize toward arbitrary attribution models with granularity. It is unclear how CMAPI would provide 0 labels (“didn’t click” or “didn’t convert”), whereas MURRE does provide this.
The Aggregate Reporting API (ARAPI) is more of a reporting mechanism than a means to provide machine learning data. While it’s been broadly speculated its output could be used to perform optimization, there has been no concrete proposal that demonstrates this. MURRE is very concrete in exactly what data finds its way to the training set with controllable levels of noise. ARAPI, to maintain privacy, could employ one of two mechanisms: k-anonymity or global differential privacy.
k-anonymity is a concern for smaller advertisers and publishers, as it could preclude them from getting the data they need to understand what they should pay, how many people they’ve reached, on what websites their ads are being shown, and so on. This would carry over to any training datasets derived from this mechanism.
The differential privacy for ARAPI is of a different flavor than in MURRE as it would be global, not local. This also raises some concerns: in order to set a particular level of privacy, an understanding of the query space must be clear. The types of queries matter, but also the volume. This is known as the “query release problem.” The more queries asked of the database, the lower the epsilon must be, and thus, the higher the noise. Given it is unclear a priori how many queries a DSP may need to run, the high level of noise could similarly disproportionately affect smaller advertisers and publishers.
Finally, both of these mechanisms require a curator of the database in the clear in order to compute the query results. While reporting is a separate issue, even for pulling a training dataset out of ARAPI, who would be this trusted curator? Is it a set of curators by applying a secure multi-party computation mechanism? Setting up MPC also has a unspecified answers as to the types of queries that can be computed, before tacking on an additional privacy mechanism.
Reporting in SPARROW (RiS) is not unlike ARAPI and proposes a kind of modified k-anonymity mechanism where query results are returned, but certain fields are censored in the output. This seems preferable to ARAPI, though some concerns still remain. RiS also has a notion of “non-protected” variables which is controversial. In addition, RiS has functionality for more real-time reporting, which is a plus, but (global) differential privacy is applied to the output which also encounters the query release problem.
Regardless, RiS, at its core, is still an aggregated reporting mechanism, which is yet to be proven effective for machine learning algorithms. For this reason, we think MURRE is a more apt proposal for this use case.
-
Duchi, J., Jordan, M., Wainwright, M. Local Privacy and Statistical Minimax Rates. 2013.
-
Dwork, C., Roth, A. The Algorithmic Foundations of Differential Privacy. 2014.
-
Smith, A., Thakurta, A., Upadhyay, J. Is Interaction Necessary for Distributed Private Learning?. 2017.
-
Wang, D., Gaboardi, M., Xu, J. Empirical Risk Minimization in Non-interactive Local Differential Privacy Revisited. 2018.
-
Wang, D., Xu, J. On Sparse Linear Regression in the Local Differential Privacy Model. 2019.
-
Zheng, K., Mou, W., Wang, L. Collect at Once, Use Effectively: Making Non-interactive Locally Private Learning Possible. 2017.