Skip to content

Commit

Permalink
Strengthen recommendation about field size
Browse files Browse the repository at this point in the history
The security consideration section has the following recommendation for
choosing parameters for circuits with joint randomness: "Field128 is
RECOMMENDED, but Field64 MAY be used with at least three proofs".

Clarify where this requirement comes from (the base proof system needs
around 128 bits of security) and strengthen this language somewhat:
"Either Field128 or Field64 with three proofs MUST be used".
  • Loading branch information
cjpatton committed Sep 23, 2024
1 parent bb01e52 commit fd9fda6
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 78 deletions.
26 changes: 19 additions & 7 deletions draft-irtf-cfrg-vdaf.md
Original file line number Diff line number Diff line change
Expand Up @@ -5521,7 +5521,7 @@ also stress that even if the IDPF is not extractable, Poplar1 guarantees that
every client can contribute to at most one prefix among the ones being
evaluated by the helpers.

## Choosing the Field Size {#security-multiproof}
## Choosing FLP Parameters {#security-multiproof}

Prio3 and other systems built from FLPs ({{flp-bbcggi19}} in particular) may
benefit from choosing a field size that is as small as possible. Generally
Expand All @@ -5543,13 +5543,25 @@ enough field ensures this computation is too expensive to be feasible. (See
Another way to mitigate this issue (or improve robustness in general) is to
generate and verify multiple, independent proofs. (See {{multiproofs}}.) For
Prio3, the `PROOFS` parameter controls the number of proofs (at least one) that
are generated and verified.
are generated and verified. In general the soundness error of the FLP is given
by the following formula:

In general, Field128 is RECOMMENDED for use in Prio3 when the circuit uses
joint randomness (`JOINT_RAND_LEN > 0`) and `PROOFS == 1`. Field64 MAY be used
instead, but `PROOFS` MUST be set to at least `3`. Breaking robustness for
`PROOFS == 2` is feasible, if impractical; but `PROOFS == 1` is completely
broken for such a small field.
~~~
(circuit_soundness + flp_soundness) ** PROOFS
~~~

where:

* `circuit_soundness` is the soundness of the validity circuit
({{flp-bbcggi19-valid}})
* `flp_soundness` is the base soundness of the proof system ({{BBCGGI19}},
Theorem 4.3)

For circuits involving joint randomness, we aim for the soundness error to be
close to `2^-128` in order to mitigate offline attacks. Such circuits MUST use
Field128 with at least one proof or Field64 with at least three proofs.
Depending on the circuit, Field64 with two proofs might have significantly
lower soundness than Field128 with one proof.

We stress that weak parameters (too small a field, too few proofs, or both) can
be exploited to attack any aggregation task using those parameters. To
Expand Down
135 changes: 64 additions & 71 deletions poc/plot_prio3_multiproof_robustness.py
Original file line number Diff line number Diff line change
@@ -1,110 +1,103 @@
# plot_prio3_multiproof_robustness.py - Plot robustness bounds for various
# parameters.
# Use `sage -python plot_prio3_multiproof_robustness.py`
# Plot robustness bounds for various parameters.
#
# sage -python plot_prio3_multiproof_robustness.py
import math
from typing import cast
from typing import TypeVar

import matplotlib.pyplot as plt

from vdaf_poc.field import Field64, Field128
from vdaf_poc.flp_bbcggi19 import FlpBBCGGI19
from vdaf_poc.vdaf_prio3 import Prio3SumVec
from vdaf_poc.field import Field64, Field128, NttField
from vdaf_poc.flp_bbcggi19 import FlpBBCGGI19, SumVec

NUM_REPORTS = 1000000000
Measurement = TypeVar("Measurement")
AggResult = TypeVar("AggResult")
F = TypeVar("F", bound=NttField)


def soundness(gadget_calls: int, gadget_degree: int, field_size: int) -> float:
def base_soundness(flp: FlpBBCGGI19[Measurement, AggResult, F]) -> float:
'''
ia.cr/2019/188, Theorem 4.3
gadget_calls - number of times the gadget is called
gadget_degree - arithmetic degree of the gadget
field_size - size of the field
'''
return gadget_calls * gadget_degree / (field_size - gadget_calls)
return sum((g_calls * g.DEGREE) / (flp.field.MODULUS - g_calls)
for (g, g_calls) in zip(flp.valid.GADGETS, flp.valid.GADGET_CALLS))


def robustness(
epsilon: float,
soundness: float,
ro_queries: int,
prep_queries: int,
num_proofs: int,
seed_bits: int) -> float:
num_proofs: int) -> float:
'''
ia.cr/2023/130, Theorem 1, assuming the bound can be modified by raising
`epsilon` to the power of the number of FLPs.
`epsilon` to the power of the number of FLPs. We're also assuming the first
term dominates, i.e., we're ignoring the seed size.
epsilon - soundness of the base FLP
soundness - soundness of the FLP
ro_queries - random oracle queries, a proxy for the amount of
precomputation done by the adversary
prep_queries - number of online attempts, a proxy for the batch size
num_proofs - number of FLPs
seed_bits - the size of the XOF seed in bits
'''
return (ro_queries + prep_queries) * epsilon**num_proofs + \
(ro_queries + prep_queries**2) / 2**(seed_bits - 1)
return (ro_queries + prep_queries) * soundness**num_proofs


def sum_vec(field_size: int, num_proofs: int, length: int) -> float:
def sum_vec(field: type[NttField], num_proofs: int, length: int) -> float:
'''
Prio3SumVec (draft-irtf-cfrg-vdaf-08, Section 7.4.3): Probability of
accepting one report in a batch of NUM_REPORTS. Assuming the asymptotically
optimal chunk length.
Maximum probability of at least 1 in 1 billion attacks on Prio3SumVec
robustness succeeding after doing 2^80 random oracle queries.
'''
bits = 1
chunk_length = max(1, length**(1/2))
vdaf = Prio3SumVec(2, length, bits, chunk_length)
valid = cast(FlpBBCGGI19[list[int], list[int], Field128], vdaf.flp).valid
gadget_calls = valid.GADGET_CALLS[0]
gadget_degree = valid.GADGETS[0].DEGREE

base_flp_soundness = soundness(gadget_calls, gadget_degree, field_size)
flp = FlpBBCGGI19(SumVec(field, length, bits, chunk_length))

# SumVec interprets the inner Mul-gadget outputs as coefficients of a
# polynomial and evaluates the polynomial at a random point. If a gadget
# output is non-zero, then the output is non-zero except with this
# probability. This is bounded by the number of roots of the polynomial.
circuit_soundness = length * bits / field_size
# Assuming we adopt the improvement from
# https://github.com/cfrg/draft-irtf-cfrg-vdaf/issues/427
soundness = chunk_length / field.MODULUS + base_soundness(flp)

return robustness(
base_flp_soundness + circuit_soundness, # ia.cr/2019/188, Theorem 5.3
2**80,
NUM_REPORTS,
soundness,
2**80, # ro queries
1_000_000_000, # prep queries
num_proofs,
vdaf.xof.SEED_SIZE * 8,
)


print(math.log2(sum_vec(Field128.MODULUS, 1, 100000)))

lengths = range(100, 10**6, 100)
plt.plot(
lengths,
[sum_vec(Field128.MODULUS, 1, length) for length in lengths],
label='Field128/1',
)
plt.plot(
lengths,
[sum_vec(Field64.MODULUS, 2, length) for length in lengths],
label='Field64/2',
)
plt.plot(
lengths,
[sum_vec(Field64.MODULUS, 3, length) for length in lengths],
label='Field64/3',
)

plt.xscale('log', base=10)
plt.yscale('log', base=2)
plt.xlabel('Length')
plt.ylabel('Prob(1 in {} accepted reports being invalid)'.format(NUM_REPORTS))
plt.title('Prio3SumvVec (field/number of proofs)')
plt.legend()
plt.grid()
plt.show()
if __name__ == '__main__':
print(-math.log2(sum_vec(Field128, 1, 100_000)))
print(-math.log2(sum_vec(Field64, 3, 100_000)))
print(-math.log2(sum_vec(Field64, 2, 100_000)))
print(-math.log2(sum_vec(Field64, 1, 100_000)))

lengths = range(100, 10**6, 100)
plt.plot(
lengths,
[sum_vec(Field128, 1, length) for length in lengths],
label='Field128/1',
)
plt.plot(
lengths,
[sum_vec(Field64, 3, length) for length in lengths],
label='Field64/3',
)
plt.plot(
lengths,
[sum_vec(Field64, 2, length) for length in lengths],
label='Field64/2',
)
# plt.plot(
# lengths,
# [sum_vec(Field64, 1, length) for length in lengths],
# label='Field64/1',
# )

plt.xscale('log', base=10)
plt.yscale('log', base=2)
plt.xlabel('Length')
plt.ylabel('Prob')
plt.title('Prio3SumvVec (field/number of proofs)')
plt.legend()
plt.grid()
plt.show()

0 comments on commit fd9fda6

Please sign in to comment.