Skip to content

Commit

Permalink
Prio3: Improve soundness of reductions (*)
Browse files Browse the repository at this point in the history
In a validity circuit we may have several values we expect to be 0. To
check that they're all zero, we interpret them as coefficients of a
polynomial and evaluate the polynomial at random point. We do this in
several places:

* Whenever `EVAL_OUTPUT_LEN > 0`
* In the `SumVec` circuit
* In the `MultihotCountVec` circuit
* In the `Histogram` circuit

This induces a soundness error of `n / |F|`, where `n` is the number of
values and $F$ is the finite field. This is significant especially for
larger inputs.

We can reduce this soundness error by reducing the degree of the
polynomial. By the Schwartz-Zippel lemma, when we evaluate a non-zero,
multivariate polynomial with degree `d` at a random point (each variable
gets a random value), the probability that the output is zero is at most
`d / |F|`. For instance, if each value is a different variable, then the
maximum degree is `1`, resulting in a `1 / |F|` soundness error.

However, the more variables the polynomial, the more randomness we need
to produce. This can become a CPU bottleneck for longer inputs.

This commit makes the following changes to Prio3 and its variants:

1. When `EVAL_OUTPUT_LEN > 0`, we include in the query randomness
   `EVAL_OUTPUT_LEN` field elements and compute the reduced output as
   the dot product of this random vector and the outputs. This improves
   the soundness error from `EVAL_OUTPUT_LEN / |F|` to `1 / |F|`.

2. We modify the `SumVec`, `MultihotCountVec` and `Histogram` circuits
   by including in the joint randomness a vector of length
   `GADGET_CALLS[0]`. For the `i`-th gadget call, we generate powers of
   `joint_rand[i]`. This results in a soundness error of `sqrt(length) /
   |F|` when the chunk length is chosen optimally.
  • Loading branch information
cjpatton committed Oct 3, 2024
1 parent 79fd0d8 commit 0940b91
Show file tree
Hide file tree
Showing 9 changed files with 79 additions and 84 deletions.
56 changes: 27 additions & 29 deletions draft-irtf-cfrg-vdaf.md
Original file line number Diff line number Diff line change
Expand Up @@ -3442,7 +3442,7 @@ def query_rand_len(self) -> int:
"""Length of the query randomness."""
query_rand_len = len(self.GADGETS)
if self.EVAL_OUTPUT_LEN > 1:
query_rand_len += 1
query_rand_len += self.EVAL_OUTPUT_LEN
return query_rand_len

def proof_len(self) -> int:
Expand Down Expand Up @@ -3600,10 +3600,9 @@ is generated as follows:
evaluation.

1. Next, reduce `out` as follows. If `EVAL_OUTPUT_LEN > 1`, then consume the
first element of `query_rand` by letting `[r], query_rand = front(1,
query_rand)`. Then let `v = r*out[0] + r**2*out[1] + r**3*out[2] + ...`.
That is, interpret the outputs as coefficients of a polynomial `f(x)` and
evaluate polynomial `f(x)*x` at a random point `r`.
first `EVAL_OUTPUT_LEN` elements of `query_rand` by letting `r, query_rand =
front(1, query_rand)`. Then let
`v = r[0]*out[0] + r[1]*out[1] + r[2]*out[2] + ...`.

1. Compute the wire polynomials just as in the prover's step (4.).

Expand Down Expand Up @@ -3908,10 +3907,10 @@ ones and zeros. Rather than use the `Range2` gadget on each element, as in the
multiplication and addition gates to simultaneously evaluate the same range
check polynomial on each element, and multiply by a constant. One of the two
`Mul` subcircuit inputs is equal to a measurement element multiplied by a power
of the joint randomness value, and the other is equal to the same measurement
element minus one. These `Mul` subcircuits are evaluated by a `ParallelSum`
gadget, and the results are added up both within the `ParallelSum` gadget and
after it.
of one of the elements of the joint randomness vector, and the other is equal
to the same measurement element minus one. These `Mul` subcircuits are
evaluated by a `ParallelSum` gadget, and the results are added up both within
the `ParallelSum` gadget and after it.

~~~ python
def eval(
Expand All @@ -3922,11 +3921,10 @@ def eval(
self.check_valid_eval(meas, joint_rand)

out = self.field(0)
r = joint_rand[0]
r_power = r
shares_inv = self.field(num_shares).inv()

for i in range(self.GADGET_CALLS[0]):
r = joint_rand[i]
r_power = r
inputs: list[Optional[F]]
inputs = [None] * (2 * self.chunk_length)
for j in range(self.chunk_length):
Expand Down Expand Up @@ -3955,7 +3953,7 @@ def eval(
| `GADGET_CALLS` | `[(length * bits + chunk_length - 1) // chunk_length]` |
| `MEAS_LEN` | `length * bits` |
| `OUTPUT_LEN` | `length` |
| `JOINT_RAND_LEN` | `1` |
| `JOINT_RAND_LEN` | `GADGET_CALLS[0]` |
| `EVAL_OUTPUT_LEN` | `1` |
| `Measurement` | `list[int]`, each element in `range(2**bits)` |
| `AggResult` | `list[int]` |
Expand Down Expand Up @@ -4029,9 +4027,9 @@ validity circuit uses the `ParallelSum` gadget to perform range checks while
achieving a smaller proof size. The `ParallelSum` gadget uses `Mul` subcircuits
to evaluate a range check polynomial on each element, and includes an additional
constant multiplication. One of the two `Mul` subcircuit inputs is equal to a
measurement element multiplied by a power of the first joint randomness value,
and the other is equal to the same measurement element minus one. The results
are added up both within the `ParallelSum` gadget and after it.
measurement element multiplied by a power of an element of the joint randomness
vector, and the other is equal to the same measurement element minus one. The
results are added up both within the `ParallelSum` gadget and after it.

~~~ python
def eval(
Expand All @@ -4043,10 +4041,10 @@ def eval(

# Check that each bucket is one or zero.
range_check = self.field(0)
r = joint_rand[0]
r_power = r
shares_inv = self.field(num_shares).inv()
for i in range(self.GADGET_CALLS[0]):
r = joint_rand[i]
r_power = r
inputs: list[Optional[F]]
inputs = [None] * (2 * self.chunk_length)
for j in range(self.chunk_length):
Expand All @@ -4071,8 +4069,8 @@ def eval(
for b in meas:
sum_check += b

out = joint_rand[1] * range_check + \
joint_rand[1] ** 2 * sum_check
out = joint_rand[-1] * range_check + \
joint_rand[-1] ** 2 * sum_check
return [out]
~~~

Expand All @@ -4085,7 +4083,7 @@ measurement is sharded. This is provided to the FLP by Prio3.
| `GADGET_CALLS` | `[(length + chunk_length - 1) // chunk_length]` |
| `MEAS_LEN` | `length` |
| `OUTPUT_LEN` | `length` |
| `JOINT_RAND_LEN` | `2` |
| `JOINT_RAND_LEN` | `1 + GADGET_CALLS[0]` |
| `EVAL_OUTPUT_LEN` | `1` |
| `Measurement` | `int` |
| `AggResult` | `list[int]` |
Expand Down Expand Up @@ -4171,10 +4169,10 @@ def eval(

# Check that each entry in the input vector is one or zero.
range_check = self.field(0)
r = joint_rand[0]
r_power = r
shares_inv = self.field(num_shares).inv()
for i in range(self.GADGET_CALLS[0]):
r = joint_rand[i]
r_power = r
inputs: list[Optional[F]]
inputs = [None] * (2 * self.chunk_length)
for j in range(self.chunk_length):
Expand Down Expand Up @@ -4203,8 +4201,8 @@ def eval(
weight_check = self.offset*shares_inv + weight - \
weight_reported

out = joint_rand[1] * range_check + \
joint_rand[1] ** 2 * weight_check
out = joint_rand[-1] * range_check + \
joint_rand[-1] ** 2 * weight_check
return [out]
~~~

Expand All @@ -4214,7 +4212,7 @@ def eval(
| `GADGET_CALLS` | `[(length + bits_for_weight + chunk_length - 1) // chunk_length]` |
| `MEAS_LEN` | `length + bits_for_weight` |
| `OUTPUT_LEN` | `length` |
| `JOINT_RAND_LEN` | `2` |
| `JOINT_RAND_LEN` | `1 + GADGET_CALLS[0]` |
| `Measurement` | `list[int]` |
| `AggResult` | `list[int]` |
{: title="Parameters of validity circuit MultihotCountVec."}
Expand Down Expand Up @@ -5761,9 +5759,9 @@ analysis of {{DPRS23}}. Thanks to Hannah Davis and Mike Rosulek, who lent their
time to developing definitions and security proofs.

Thanks to Junye Chen, Henry Corrigan-Gibbs, Armando Faz-Hernández, Simon
Friedberger, Tim Geoghegan, Albert Liu, Brandon Pitman, Mariana Raykova, Jacob
Rothstein, Shan Wang, Xiao Wang, Bas Westerbaan, and Christopher Wood for
useful feedback on and contributions to the spec.
Friedberger, Tim Geoghegan, Albert Liu, Brandon Pitman, Mariana Raykova,
Michael Rosenberg, Jacob Rothstein, Shan Wang, Xiao Wang, Bas Westerbaan, and
Christopher Wood for useful feedback on and contributions to the spec.

# Test Vectors {#test-vectors}
{:numbered="false"}
Expand Down
37 changes: 17 additions & 20 deletions poc/vdaf_poc/flp_bbcggi19.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ def query_rand_len(self) -> int:
"""Length of the query randomness."""
query_rand_len = len(self.GADGETS)
if self.EVAL_OUTPUT_LEN > 1:
query_rand_len += 1
query_rand_len += self.EVAL_OUTPUT_LEN
return query_rand_len

def proof_len(self) -> int:
Expand Down Expand Up @@ -359,12 +359,10 @@ def query(

# Reduce the output.
if self.valid.EVAL_OUTPUT_LEN > 1:
([r], query_rand) = front(1, query_rand)
r_power = r
(rand, query_rand) = front(self.valid.EVAL_OUTPUT_LEN, query_rand)
v = self.field(0)
for out_elem in out:
v += r_power * out_elem
r_power *= r
for (r, out_elem) in zip(rand, out):
v += r * out_elem
else:
[v] = out

Expand Down Expand Up @@ -640,7 +638,6 @@ class Histogram(
length: int
chunk_length: int

JOINT_RAND_LEN = 2
EVAL_OUTPUT_LEN = 1

def __init__(self, field: type[F], length: int, chunk_length: int):
Expand All @@ -663,6 +660,7 @@ def __init__(self, field: type[F], length: int, chunk_length: int):
self.GADGET_CALLS = [(length + chunk_length - 1) // chunk_length]
self.MEAS_LEN = self.length
self.OUTPUT_LEN = self.length
self.JOINT_RAND_LEN = 1 + self.GADGET_CALLS[0]

# NOTE: This method is excerpted in the document, de-indented. Its
# width should be limited to 69 columns after de-indenting, or 73
Expand All @@ -677,10 +675,10 @@ def eval(

# Check that each bucket is one or zero.
range_check = self.field(0)
r = joint_rand[0]
r_power = r
shares_inv = self.field(num_shares).inv()
for i in range(self.GADGET_CALLS[0]):
r = joint_rand[i]
r_power = r
inputs: list[Optional[F]]
inputs = [None] * (2 * self.chunk_length)
for j in range(self.chunk_length):
Expand All @@ -705,8 +703,8 @@ def eval(
for b in meas:
sum_check += b

out = joint_rand[1] * range_check + \
joint_rand[1] ** 2 * sum_check
out = joint_rand[-1] * range_check + \
joint_rand[-1] ** 2 * sum_check
return [out]

# NOTE: The encode(), truncate(), and decode() methods are excerpted
Expand Down Expand Up @@ -767,7 +765,6 @@ class MultihotCountVec(
# Class object for the field.
field: type[F]

JOINT_RAND_LEN = 2
EVAL_OUTPUT_LEN = 1

def __init__(self,
Expand Down Expand Up @@ -816,6 +813,7 @@ def __init__(self,
]
self.MEAS_LEN = self.length + self.bits_for_weight
self.OUTPUT_LEN = self.length
self.JOINT_RAND_LEN = 1 + self.GADGET_CALLS[0]

# NOTE: This method is excerpted in the document, de-indented. Its
# width should be limited to 69 columns after de-indenting, or 73
Expand All @@ -830,10 +828,10 @@ def eval(

# Check that each entry in the input vector is one or zero.
range_check = self.field(0)
r = joint_rand[0]
r_power = r
shares_inv = self.field(num_shares).inv()
for i in range(self.GADGET_CALLS[0]):
r = joint_rand[i]
r_power = r
inputs: list[Optional[F]]
inputs = [None] * (2 * self.chunk_length)
for j in range(self.chunk_length):
Expand Down Expand Up @@ -862,8 +860,8 @@ def eval(
weight_check = self.offset*shares_inv + weight - \
weight_reported

out = joint_rand[1] * range_check + \
joint_rand[1] ** 2 * weight_check
out = joint_rand[-1] * range_check + \
joint_rand[-1] ** 2 * weight_check
return [out]

# NOTE: The encode(), truncate(), and decode() methods are excerpted
Expand Down Expand Up @@ -915,7 +913,6 @@ class SumVec(
chunk_length: int

field: type[F]
JOINT_RAND_LEN = 1
EVAL_OUTPUT_LEN = 1

def __init__(self, field: type[F], length: int, bits: int, chunk_length: int):
Expand Down Expand Up @@ -943,6 +940,7 @@ def __init__(self, field: type[F], length: int, bits: int, chunk_length: int):
]
self.MEAS_LEN = length * bits
self.OUTPUT_LEN = length
self.JOINT_RAND_LEN = self.GADGET_CALLS[0]

# NOTE: This method is excerpted in the document, de-indented. Its
# width should be limited to 69 columns after de-indenting, or 73
Expand All @@ -956,11 +954,10 @@ def eval(
self.check_valid_eval(meas, joint_rand)

out = self.field(0)
r = joint_rand[0]
r_power = r
shares_inv = self.field(num_shares).inv()

for i in range(self.GADGET_CALLS[0]):
r = joint_rand[i]
r_power = r
inputs: list[Optional[F]]
inputs = [None] * (2 * self.chunk_length)
for j in range(self.chunk_length):
Expand Down
6 changes: 3 additions & 3 deletions test_vec/vdaf/Prio3Histogram_0.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"prep": [
{
"input_shares": [
"e720f2d625ee3cabce61d583c8c4054e82e8487025764348020264792b3d100f0d8c76f65caf04ee0e22373be0d61ac5fa6e2f2866078b31b90537e24416fad1d878d8b7b93954e80a0a008ae08698e74409c646c5089bf508d7b32589a4442c84c94b77dd83e10d4cbdcb0a8e9084ba58812ef6c40e078587f3c82140facd7e9f1a452be3ba2c427ccee36d355426f984ebb03d6cfa47e1fa9a22e80b0a45797d3c96c01b92097da6b227b76e15dbe1995ffd32815553c38fc0ce8a7963e9755af5c8725287f9293619981371abdf17ed4226cb0ec5ab002d6b911674449ae82b6e8d6d731351b391305d930b58d0e2404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f",
"e720f2d625ee3cabce61d583c8c4054e82e8487025764348020264792b3d100f0d8c76f65caf04ee0e22373be0d61ac5fa6e2f2866078b31b90537e24416fad1d878d8b7b93954e80a0a008ae08698e74409c646c5089bf508d7b32589a4442c84c94b77dd83e10d4cbdcb0a8e9084ba58812ef6c40e078587f3c82140facd7e6a4d6942338c87ab5336de984fca87d6315bd0cd55be021a5e8c95cb2f58d403209e06a16b0e535a34828e56812b7a3f995ffd32815553c38fc0ce8a7963e9758fc2a45b02b69ec05eb19de856357e3a3fd3063b2501f1c7e5791e3350f60a5e870c1d8d239707d61f61f6f3f8413185404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f",
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"
],
"measurement": 2,
Expand All @@ -40,8 +40,8 @@
],
"prep_shares": [
[
"9f17b88098bfb80caf9ede18f73e1f59047bf192a96088cc39746f77e3ea46e38eea1655b3984d18f463017cf08b4573db819c87c5c7cfa8eb23922c011d915a8cdf89ee9ba292d685123b3aaceeb6f9ff2039f3ec56c54ddbc7263762d35452064ddc2301a2ff2176338dd52a09fdadd442cddcbe5d10dafe0d92551d81eac7",
"62e8477f674047f3346121e708c1e0a63e7e8539fa49a77c81079113696d3384c4f1afc98e06f8da4623d5c35be0f2232296fe2274e9cefd7421cc98c25a4c413110eee2776703e3ae98d85bb97a6366c4b297f11de9f137b3448ccb5e3c9188c27dda399f3c8341c7476370573e51b6ebe601061807bb886fc55c2161ce436e"
"fe948d4cd76062bf22701bb43996a49cba61d1731de0e8308ff530bcdfe026ec8eea1655b3984d18f463017cf08b457350a16a88584ed7c28488e505cfcdb4d88cdf89ee9ba292d685123b3aaceeb6f9b7e327bc346ea7cf4b08607817838bc6064ddc2301a2ff2176338dd52a09fdadd442cddcbe5d10dafe0d92551d81eac7",
"036b72b3289f9d40c18fe44bc6695b63afc34d8cb6e960d8b976cb0765e57775c4f1afc98e06f8da4623d5c35be0f223ae763022e162c7e3bfbc78bff4a928c33110eee2776703e3ae98d85bb97a6366c4b297f11de9f137b3448ccb5e3c9188c27dda399f3c8341c7476370573e51b6ebe601061807bb886fc55c2161ce436e"
]
],
"public_share": "064ddc2301a2ff2176338dd52a09fdadd442cddcbe5d10dafe0d92551d81eac7c27dda399f3c8341c7476370573e51b6ebe601061807bb886fc55c2161ce436e",
Expand Down
6 changes: 3 additions & 3 deletions test_vec/vdaf/Prio3Histogram_1.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,9 @@
],
"prep_shares": [
[
"60d70d50d44a19675211ebb9f2df59dc87d391a154de2a7b18cb3afb531c22618198e704f75ba96676c13e934c8746b9b9fad1a001f881214456babaf803fdc87b8fbe64d3a62639873674bf0a4218dec7045502cc8d7655714a1fdb5a26524123e2aa64f2e271ebb1ef64eea728cb764ef56111139b6b57b6062b056dc35bed65b3e30205531b610d546de28a6b7c7cc058087324206afad931cea724e2285c",
"033bff2174efd7f0edd1534d1054073c05e16f96a227465f0eec5ee6f86d25533431985cb562b9d20a4295522a352a759430fdfd38a22f9b5037be7ba9340da15401c6b870addc1c3f510e7ad00f47221343d7bce9f229b017076b06ce9330a6d096c94ec36ae3d772aaba20f671ab13f9c9520e7327eb51b157b1f85998871782c591e1ce996072e1f096b5991133f1d6ab883b98ec6a028b1de85eefed6989",
"9fedf28db7c50ea8871cc1f8fccb9ee7e40f12d9e53ed79f09c5f0132c8501c5e6b477e489edc6f4e4089fbefdd015a7c8ae22a7debbc76ef75c51ab3e9c45594e85bc69d1b7f52fa709f8fa8eb410481c7b149cdeedeb456e74903fa5186d0de0ede9e87d84ffacb9aefa677afca9e41e392104f4d325733744731b47055cdfed585479d34bf381eb8c5a1655338d24d04951ef27510d46ac2d45d22b5fc6c2"
"54c772db149e08bf8f37653ac9ce2d30169d05142fc8a851d1544196fedad6ce8198e704f75ba96676c13e934c8746b94468872d7f74f22a439558ac6b063dc87b8fbe64d3a62639873674bf0a4218de8b92f481022a2ec78b76fa53f2e2f9f423e2aa64f2e271ebb1ef64eea728cb764ef56111139b6b57b6062b056dc35bed65b3e30205531b610d546de28a6b7c7cc058087324206afad931cea724e2285c",
"b4517efa1067670f78b521be727df88530ae81f2b870c00f22f3ee5bb93ede5a3431985cb562b9d20a4295522a352a75c6c287ce6cdfa2efefafb2c6112c18015401c6b870addc1c3f510e7ad00f47224c580be23a06d339489c891e7f32e307d096c94ec36ae3d772aaba20f671ab13f9c9520e7327eb51b157b1f85998871782c591e1ce996072e1f096b5991133f1d6ab883b98ec6a028b1de85eefed6989",
"f9e60e2adafa8f31dc127907c4b3d9492a798c0af50bdf183d345a03c1f5934fe6b477e489edc6f4e4089fbefdd015a70bafe2492d02e41059a5be6e63a2faf94e85bc69d1b7f52fa709f8fa8eb4104820d840f7563e8b4a07b396ae5cbd12f8e0ede9e87d84ffacb9aefa677afca9e41e392104f4d325733744731b47055cdfed585479d34bf381eb8c5a1655338d24d04951ef27510d46ac2d45d22b5fc6c2"
]
],
"public_share": "65b3e30205531b610d546de28a6b7c7cc058087324206afad931cea724e2285c82c591e1ce996072e1f096b5991133f1d6ab883b98ec6a028b1de85eefed6989ed585479d34bf381eb8c5a1655338d24d04951ef27510d46ac2d45d22b5fc6c2",
Expand Down
6 changes: 3 additions & 3 deletions test_vec/vdaf/Prio3MultihotCountVec_0.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"prep": [
{
"input_shares": [
"e2bb7419a8ac96a1c6def1bed78dcb074557af87236442363aa49be4fd351b11b64bede210be55b253caa20a0f75703e295aa329cd650b825d3d4492d46d2fb362d5c7a84cb3dc77420ae9fb319a83b91a5ed94b3fee03d209e78f1b2561041a66cf7dff4a43e15165bcaed22955b547461b80bb28663b502ad8b1536aa6d3cffdd56552a27dab37d3921be5ad85e990d6182143dd4b359053d6b41b58a260a313f4d156c3759cd89beabcc371a4d9024e9c849a424fc3be98766880bf468f20b3b350ceca0a3bf245a02778b7af045493d680d9a3e0261d17a21ccdee91bde8a59083bf43fe5bba1e589ce2d4ee0fe93bccb14a0d5fa0bf79df139a95ed1ee669a3728461801d49f0ded99bfccc9a7c404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f",
"e2bb7419a8ac96a1c6def1bed78dcb074557af87236442363aa49be4fd351b11b64bede210be55b253caa20a0f75703e295aa329cd650b825d3d4492d46d2fb362d5c7a84cb3dc77420ae9fb319a83b91a5ed94b3fee03d209e78f1b2561041a66cf7dff4a43e15165bcaed22955b547461b80bb28663b502ad8b1536aa6d3cffdd56552a27dab37d3921be5ad85e990d6182143dd4b359053d6b41b58a260a36444c50596526e58032cf8d75335a776d8e856f751d5b9972dcb6d5e9df41e1a13612efca2bf4dc3a35d88e64bde741e93d680d9a3e0261d17a21ccdee91bde85440901071218a3ab71661cef25d4275b17fdfedfdd8a9e6e48a0ebcb73f8fec09f6945689cb0a789221792d689e2ab2404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f",
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"
],
"measurement": [
Expand Down Expand Up @@ -46,8 +46,8 @@
],
"prep_shares": [
[
"13aad47c9d83b173af1cd7554e83edf113c720f5e32182b2b8ff5de4dd9ace9d02fd704ab2110f43db49149006bbdaa839b33e57b75715482852da03641f78ea5750d8f4d5253d179868e3c2a919f186c05a35478c60d198dd0963b342597f76f626f32389f3abd8f1007f22683246938f85d46fdcf067e79c9b6b088a0c70ba",
"ee552b83627c4e8c34e328aab17c120e79df617375adc7bd6cbd15d818368162a65c8d883597126ed7fd9cfb0a6125e2a5360202d5d1473123636b742f47cbec53b4981c55755bcb6c5cefa3a916372b85c0804a37fa78c9abc3082b5bdda6255728b4e324470bb29993bf18e20714421c8e06f4c0622e3641eb50f24fed1117"
"8863bd7450266fb467f769f2a71299b25fd53feb40543a0535a6fd249bf328ce02fd704ab2110f43db49149006bbdaa86845781af4ee4cd4721684b8b388a08b5750d8f4d5253d179868e3c2a919f186474a786e5fe64faeda411aa0143980c6f626f32389f3abd8f1007f22683246938f85d46fdcf067e79c9b6b088a0c70ba",
"799c428bafd9904b7c08960d58ed664d25a41f1c1169561d342e081a6064739ea65c8d883597126ed7fd9cfb0a6125e2be414c8b3e13fe8594f9601eaf92710a53b4981c55755bcb6c5cefa3a916372b85c0804a37fa78c9abc3082b5bdda6255728b4e324470bb29993bf18e20714421c8e06f4c0622e3641eb50f24fed1117"
]
],
"public_share": "f626f32389f3abd8f1007f22683246938f85d46fdcf067e79c9b6b088a0c70ba5728b4e324470bb29993bf18e20714421c8e06f4c0622e3641eb50f24fed1117",
Expand Down
Loading

0 comments on commit 0940b91

Please sign in to comment.