# Point-programmable vector commitments {#ppvc_manual} A point-programmable vector commitment binds a vector `x` in `(Z/2^s Z)^n` and still lets one hidden coordinate be chosen after the commitment is published. `n` is a power of two, the bit length of the input type, and at most 2^16. `s` is the `Width` parameter, from 1 to 64. The manual construction is `dpf::ppvc`. `dpf::k_ppvc` is `K` independent copies of that object. The committer samples an index `i` and builds `s` aligned 1-bit DPF pairs there, the same point key as [DPF basics](@ref basics_body). Both roots of every pair are bound with a Naor commitment under a public matrix `A`. Opening releases one key from each pair, together with a shift `delta = xi - i`. Off `i`, the two keys of a pair evaluate to the same bit. At `i`, they evaluate to opposite bits. Choosing the side therefore writes an arbitrary value into that one coordinate and leaves every other coordinate fixed. The shift moves the written coordinate from `i` onto the public target `xi`. The opening carries `delta`, not `i` and not `xi`. `open(st, mu, tau, xi)` has two modes. - `mu = 0` programs the coordinate. After rotation, entry `xi` equals `tau`. - `mu = 1` programs the sum of every coordinate. That sum equals `tau`. Those two maps are bijections on `Z/2^s Z`. Programming one of them programs the other. ```cpp using scheme = dpf::ppvc; const auto pp = scheme::setup(); const auto [com, st] = scheme::commit(pp); const std::uint8_t xi = 40; const auto op = scheme::open(st, 0, 0x5a, xi); const auto x = scheme::eval(op); // hidden indexing const auto rotated = scheme::eval_rotated(op); // value 0x5a sits at xi const bool ok = scheme::accept(pp, com, op, x, xi); ``` `setup` samples `A`. `setup_from_seed` expands one 128-bit seed into the same matrix, which is the common random string when many sessions share it. `commit` samples `i`. `commit_at` uses an index the caller already chose. The shift hides `i` when that index was sampled independently of `xi`. `commit_from_seed` and `commit_at_from_seed` rerun key generation from a replica seed. Seed expansion keeps its counter in thread-local storage, so two expansions on one thread must not overlap. ## What an opening proves {#ppvc_verify} `verify` checks each opened root against its Naor string. `accept` also checks the programmed statement: the rotated coordinate when `mu` is 0, the column sum when `mu` is 1. Correction words travel with the opened key. They are not inside the commitment. `verify` sees one side of each pair. `check_well_formed` is the check on a replica the committer still holds: shared correction words, party bits 0 and 1, both Naor openings, and exactly one place where the two keys disagree, at the recorded index, with payload 1. `audit` expands a seed and accepts when the published commitment matches that expansion and the replica is well formed. `k_ppvc` asks for the same checks on every copy, and for distinct hidden indices. `combine_rotated` adds the rotated vectors in `Z/2^s Z`. Reprogramming copy `r` changes coordinate `xi[r]` of that sum. The commitment is `2 * s * (3 * 128 + Sigma)` bits. `Sigma` defaults to 128 and must be a multiple of 8. The generator is `dpf::prg::aes128` unless another 128-bit PRG is named. **Defined in**\n @ref dpf/ppvc.hpp **Try**\n @ref mwe/ppvc.cpp Naor's string commitment is Moni Naor, "Bit Commitment Using Pseudorandomness," Journal of Cryptology 4(2), 1991, pp. 151–158. The point keys are the Boyle–Gilboa–Ishai construction named in [DPF basics](@ref point_functions).