#7522·flower

[Bug]: SecAgg+ uses non-cryptographic PRG for mask generation

Author: AlessandroPerezCreated Jul 2, 2026Updated Jul 17, 2026

Describe the bug

pseudo_rand_gen in framework/py/flwr/common/secure_aggregation/secaggplus_utils.py collapses the input seed to a 32-bit integer and then uses np.random.RandomState to generate the private and pairwise masks.

Why this is a problem:

  • np.random.RandomState is not a cryptographically secure pseudo-random generator
  • XOR-compressing an arbitrary length secret into a 32-bit value throws away almost all entropy before the generator even starts

This weakens the privacy guarantee that the masks are supposed to provide.

A possible fix is to replace np.random.RandomState with a cryptographic PRF/XOF such as SHAKE256 or AES-CTR-DRBG, and use the full seed/key rather than compressing it to 32 bits.

Steps/Code to Reproduce

Mask generation helper used by classical SecAgg+:

from flwr.common.secure_aggregation.secaggplus_utils import pseudo_rand_gen

# This is the same path used inside secaggplus_mod.py for both
# the private mask (rd_seed) and the pairwise masks (ECDH shared_key).
mask = pseudo_rand_gen(b"a" * 32, 1024, [(10,)])

The implementation:

# framework/py/flwr/common/secure_aggregation/secaggplus_utils.py
def pseudo_rand_gen(seed, num_range, dimensions_list):
    assert len(seed) & 0x3 == 0
    seed32 = 0
    for i in range(0, len(seed), 4):
        seed32 ^= int.from_bytes(seed[i : i + 4], "little")
    gen = np.random.RandomState(seed32)

Expected Results

  • Mask generation should use a cryptographically secure pseudo-random function / generator
  • The full entropy of the input secret should be preserved, not compressed to 32 bits
  • An attacker who observes mask values should not be able to reconstruct the seed or predict other mask entries

Actual Results

  • The input seed is XOR-compressed into a 32-bit integer, regardless of its original length
  • np.random.RandomState is used to generate the masks. This generator is not cryptographically secure and is vulnerable to state-recovery attacks given sufficient output
  • The privacy guarantee of the SecAgg+ masks is weakened