Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chilldkg: fix enc_secshare deserialization #76

Merged

Conversation

siv2r
Copy link
Contributor

@siv2r siv2r commented Jan 14, 2025

While deserializing recovery data, for enc_secshare, we should use Scalar.from_bytes(...) instead of Scalar(int_from_bytes(...)). The latter does not raise a ValueError for overflowed values; it silently applies modulo to produce a valid Scalar element!

Scalar(int_from_bytes(...)) is also used for generating pads (self_pad and ecdh). I think this is acceptable since we’re generating random numbers, not deserializing data.

Copy link
Collaborator

@jonasnick jonasnick left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK. Thanks @siv2r.

Scalar(int_from_bytes(...)) is also used for generating pads (self_pad and ecdh). I think this is acceptable since we’re generating random numbers,

Acceptable, but probably better to do this in a consistent way unless you really want to wrap around.

@siv2r
Copy link
Contributor Author

siv2r commented Jan 15, 2025

The wrapping around (when creating a scalar from the tagged hash output) occurs in both schnorr_sign and schnorr_verify:

k0 = (
int_from_bytes(tagged_hash(tag_prefix + "/nonce", t + P.to_bytes_xonly() + msg))
% GE.ORDER
)

e = (
int_from_bytes(tagged_hash(tag_prefix + "/challenge", sig[0:32] + pubkey + msg))
% GE.ORDER
)

I assumed we generally don’t want to raise a ValueError when generating random scalars, so I left it as-is instead of switching to Scalar.from_hex(...) when generating the pads. Since this ValueError might happen with only negligible probability, we could change it for consistency. Let me know if you’d prefer that, and I’d be happy to update it.

@real-or-random
Copy link
Collaborator

I think the proper way is to change secp256k1proto to split APrimeFE.from_int into a APrimeFE.from_int_wrapping, which wraps around, and a APrimeFE.from_int_checked, which raises OverflowError. (APrimeFE is the abstract superclass of Scalar).

Then we can use the appropriate function everywhere. (Not sure if we want to touch bip340.py though, I tried to keep this as close as possible to the reference code in the BIP, so it's okay to work with integers there and keep the explicit %.)

Scalar(int_from_bytes(...)) is also used for generating pads (self_pad and ecdh). I think this is acceptable since we’re generating random numbers,

Acceptable, but probably better to do this in a consistent way unless you really want to wrap around.

The wrapping there was intentional: Wrapping is not only acceptable when the input is uniformly random (or a hash), it yields simpler code because it removes an error path. This was the rationale for why we wrap in BIP340, after a long discussion.

But the ECDH implementation is supposed to replicate whatever libsecp256k1 does, and it errors out in case of overflow...

And then, if we wrap in ECDH, we may as well wrap in self_pad for consistency. Sigh.

Anyway, ACK. Happy to see a PR that implements the above changes but we can also do it later.

@real-or-random real-or-random merged commit 775d20f into BlockstreamResearch:master Jan 15, 2025
1 check passed
@jonasnick
Copy link
Collaborator

I think the proper way is to change secp256k1proto to split APrimeFE.from_int into a APrimeFE.from_int_wrapping

Agree

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants