Files
zeekay d1cc69af98 Make the Schnorr challenge cover the message it signs
The signer and the verifier each built c = H(R || Y || m) by passing the
concatenation to curve.FromHash, which does not hash: it truncates its
input to the group order's byte length and reads it big-endian, the SECG
convention for an ECDSA digest. Y and m fell off the end, so the
challenge was a function of R alone and one signature verified under
every message.

The derivation now lives in one place and hashes, each piece length- and
domain-separated, with the digest read wide.
2026-09-01 19:31:18 -07:00

20 lines
672 B
Go

package sign
import (
"github.com/luxfi/threshold/pkg/hash"
"github.com/luxfi/threshold/pkg/math/curve"
"github.com/luxfi/threshold/pkg/math/sample"
)
// challenge is the Schnorr challenge c = H(R ‖ Y ‖ m). It lives in one place so
// the signer and the verifier cannot drift apart, and it hashes, which is what
// makes it cover the message: each piece goes in length- and domain-separated,
// and the digest is read wide.
func challenge(group curve.Curve, R, public curve.Point, message []byte) (curve.Scalar, error) {
h := hash.New()
if err := h.WriteAny(R, public, message); err != nil {
return nil, err
}
return sample.Scalar(h.Digest(), group), nil
}