> Another naming question, should it be dsa_slh_shake128, or maybe > dsa_slh128_shake ?
We could stick to the spec param names like slh_dsa_shake_128s. Also do you prefer slh_dsa or dsa_slh prefix? > Do you think it would be reasonable to drop the sha2 variants in the > first iteration? Yes, I think its fine to just have shake variants in the first iteration. On Wed, Jan 29, 2025 at 10:15 AM Niels Möller <[email protected]> wrote: > Zoltan Fridrich <[email protected]> writes: > > > We want to use SLH-DSA for document signing. I think I will need to add > the > > pure and prehash API signing functions. But otherwise whether shake or > sha2 > > variant is available it does not matter. > > Do you think it would be reasonable to drop the sha2 variants in the > first iteration? Then we wouldn't get the complexities of dealing with > either "normal" or "compressed" addresses. > > >> For the api, I think it should be possible to support "pure" signatures > >> without requiring all of the message in memory at once, using a > >> init/update/final-style interface for sign and verify, based on the > >> update function of the underlying hash. Is that worth while? > > > > Sounds like a good idea. I can add it in. > > Unfortunately, after a closer look I don't think this is doable. For > pure signing, the message is hashed twice, once with the secret prf to > produce the randomizer, and then together with randomizer and public key > to produce the "digest". It should be possibly to do for the verify > operation only, but I don't think that's worth the effort. > > > It seems to be a typo in the comment. When I checked the logic it is > indeed > > pk: [PUB_SEED || root] > > That's good. > > >> For the Nettle api, I would also consider to not include the pubkey as > >> part of the secret key, but instead pass both pubkey and secret key to > >> the secret key functions. Similar to, e.g., ed25519_sha512_sign. > > > > That seems redundant to me when the spec defines a secret key to contain > > the public key too. > > Did you mean that the secret key shouldnt contain the public key part? > > I'm thinking of something analogous to Nettle's ed25519 api, > > void > ed25519_sha512_sign (const uint8_t *pub, > const uint8_t *priv, > size_t length, const uint8_t *msg, > uint8_t *signature); > > int > ed25519_sha512_verify (const uint8_t *pub, > size_t length, const uint8_t *msg, > const uint8_t *signature); > > Here, the pub argument is the same for both functions, and the priv > argument is the additional private information needed for signing. If we > do this for dsa-slh, pub would include PK.seed and PK.root, and priv > would include SK.seed and SK.prf, which seems straightforward to me. > > (Signing applications would still be free to store public and private > parts together whenever convenient). > > Nettle isn't totally consistent though, some older signing functions > take only a private key argument which then needs to include everything, > others take public key as an additional argument. But I prefer the > separate style (it's seems more flexible, and it's also more explicit > about what's public and private), if there's no strong reason to do it > differently. > > >> I think I would prefer separate top-level functions for the different > >> algorithm variants, rather than the enum slh_dsa_mode. They could all > >> call the same internal function, passing the appropriate params struct > >> as argument. > > > > What about the pure and pre-hash variants and init, update and final api? > > Can you describe how you would like the API to look like? > > Since it seems we can't have the init/update/final variant, I would suggest > > void > dsa_slh_shake128_sign (const uint8_t *pub, > const uint8_t *priv, > size_t length, const uint8_t *msg, > uint8_t *signature); > void > dsa_slh_shake128_verify (const uint8_t *pub, > size_t length, const uint8_t *msg, > const uint8_t *signature); > > for the pure variant, and > > void > dsa_slh_shake128_ph_sha256_sign (const uint8_t *pub, > const uint8_t *priv, > const uint8_t *digest, > uint8_t *signature); > void > dsa_slh_shake128_ph_sha256_verify (const uint8_t *pub, > const uint8_t *digest, > const uint8_t *signature); > > for the prehash with sha256 variant. There will be lots of functions, > but they should all be simple wrappers around some internal function > like > > void > _nettle_dsa_slh_sign_internal (const struct dsa_slh_variant *alg, > const uint8_t *pub, > const uint8_t *priv, > size_t prefix_length, const uint8_t > *prefix, > size_t length, const uint8_t *msg, > uint8_t *signature); > > (with the prefix, including the extra zero bytes or prehash object id, > passed as a separate argument to avoid allocation and copying of the > message). > > For link-time dependencies, it's desirable that code specific to one > slh-dsa variant is referenced indirectly via the struct dsa_slh_variant, > and that source files are organized so that applications using only a > single variant don't link-depend on unrelated code. > > (The name dsa_slh_variant is a tentative name I made up, feel free to > use something different). > > Another naming question, should it be dsa_slh_shake128, or maybe > dsa_slh128_shake ? There's a shake128 algorithm, but that's *not* used > for dsa-slh, it uses shake256. Instead, 128/192/256 refers to the size > of the values used internally in slh-dsa and in the resulting signature. > > >> It's unclear how this differs from _nettle_treehash further above? Or in > >> general, whats the meaning of "x1" suffix on some functions? > > > > I don't exactly know but I think it is some kind of optimization where > the > > number determines how many addresses are processed at once. > > Here is an example of x8 from the reference implementation > > > https://github.com/sphincs/sphincsplus/blob/7ec789ace6874d875f4bb84cb61b81155398167e/sha2-avx2/utilsx8.c#L38 > > I don't get exactly how that 8-way operations works. It would be > interesting to know what performance improvements they see from that > (if it's a significant performance boost, we should consider adding > something like that later). > > And it's still unclear to me what's the difference between > _nettle_treehash and _nettle_treehashx1 in the patch. > > >> Not sure I get why wots_k_mask is used? Is it intended to improve > >> sidechannel-silence or performance? > > > > To me it seems to only switch the logic to generate WOTS signatures. I > > don't know whether it aims to improve either performance or > > sidechannel-silence. > > I think it makes the code harder to understand when signature bytes are > copied out to the result in a conditional in the middle a loop (both for > wots and for the merkle inclusion proofs). I like the structure in my > prototype better, see > https://git.lysator.liu.se/nisse/poc-slh-dsa/-/blob/main/wots.c?ref_type=heads#L120 > > wots_chain (public_seed, addr, 0, msg, sig, sig); > sha3_256_update (ctx, _SLH_DSA_128_SIZE, > wots_chain (public_seed, addr, msg, 15 - msg, sig, > pub)); > > where first line produces the signature, and second line extends the > chain to produce the corresponding public key. But you probably don't > want to do any extensive refactoring now. > > To aid later refactoring, it would help with unit tests for the various > components (even just using the intermadiate values from the top-level > tests > is helpful; that's what I did for my prototype). > > Another useful addition would be benchmarking in > examples/hogweed-benchmark.c. > > Regards, > /Niels > > -- > Niels Möller. PGP key CB4962D070D77D7FCB8BA36271D8F1FF368C6677. > Internet email is subject to wholesale government surveillance. > > _______________________________________________ nettle-bugs mailing list -- [email protected] To unsubscribe send an email to [email protected]
