Skip to main content

fors_sign_into

Function fors_sign_into 

Source
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.