pub fn fors_sign_into<P: Params>(
md: &[u8],
sk_seed: &[u8],
pk_seed: &[u8],
adrs_template: &Adrs,
out: &mut [u8],
) -> Result<(), SlhDsaError>Expand description
Streaming variant of fors_sign — writes the K * (1 + A) * N
byte FORS signature directly into the start of out (which must
be at least that size).
Each per-tree block is written as sk (N) || auth path (A * N)
directly into its slot inside out, avoiding the transient
per-call Vec<u8> heap buffer.
adrs_template is read-only — a local clone is taken internally so the
caller’s address state is not mutated. The save/restore of
key_pair_address inside the per-tree loop already guarantees that the
function does not depend on its own residual mutation across iterations,
so the local clone is semantically equivalent to the previous in-place
mutation pattern.
§Feature: sca-fors-dummy-siblings (T1-D)
When enabled, the inner per-FORS-tree loop is replaced by a single
full-tree BDS streaming traversal: for each FORS tree i, all
2^A leaves at positions [base, base + 2^A) are produced in
fixed order (base = i * 2^A), regardless of the secret index
idx. The leaf secret and the A auth-path sibling nodes are
extracted branchlessly during the climb, via silentops::ct_copy
guarded by silentops::ct_eq_u32. The address sequence absorbed by
Keccak (set_tree_index(base + 0..base + 2^A - 1) and the matching
internal-merge addresses) is then a deterministic function of i
only — the per-bit template oracle of Kannwischer COSADE 2018
(ePrint 2018/673) collapses, since no
idx-dependent address ever reaches the PRF. Cost: roughly 2×
the FORS hash count vs the FIPS-205 default path (one full
tree vs the auth-path subtrees that sum to ~2^A - 1 leaves).
Output bytes are byte-identical to the default path on every
input.
§Historical correction
The earlier SCA-annex draft described T1-D as “compute both
possible siblings (s=0 and s=1) at fixed positions and select
branchlessly”. That framing is wrong: FIPS-205 Algorithm 16 has
s = floor(idx / 2^j) XOR 1 (multi-bit, taking values in
[0, 2^(A-j)) at level j), so the sibling sits at one of
2^(A-j) idx-dependent positions, not at a fixed pair. The
only mechanism that produces an idx-independent address
sequence at the same asymptotic cost is the full-tree streaming
traversal implemented here.