I believe the library will access uninitialized fields. Is that right?
That is right, good catch.
There could be multiple solutions:
- As you suggest, the magic can be used as a version field.
- The s2c_opening struct itself contains a magic field. Instead of calling
secp256k1_schnorrsig_s2c_opening_init(s2c_opening)
to initialize it inside the signing function, we could have the caller do this instead and check that the magic is set properly.
- not adding these fields to extraparams but add another function secp256k1_schneorrsig_sign_s2c instead.
It seems to me that option 2 is worse, as if the opening magic is not set properly (e.g. by a user using the old headers with the new library), then the function would error. This is better than proceeding silently, but it still is incompatible and forces the user act. The alternative to erroring is to ignore these fields to maintain compatibility, but that would be strange for new library users that want to use the functionality and don’t see a proper error message when they fail to initialize the opening struct.
Option 3 seems backwards as the point of secp256k1_schnorrsig_extraparams
struct was, I presume, to be able to extend it in a backwards compatible fashion.
Option 2 probably makes sense to do for the same reason that the extraparams struct is initialized by the user - to prevent corrupting memory in case the user passes the wrong pointer, and to possibly use it as a version field in the future.
TL;DR: I think defining a new magic in the extraparams struct is the best option, and we should also have the caller initialize the secp256k1_schnorrsig_s2c_opening
struct with the magic. What do you think?
As a sidenote: maybe it would be a good to introduce a version check or init function for this library in general, so that if breaking changes are necessary in the future, it could be caught early at runtime.