package secp256k1 // The hot path is verification, and for 32-byte messages (the only length // Nostr uses) it is delegated to btcec's BIP-340 implementation. That package // carries the same pure-Go 5x52/10x26 field arithmetic that orly's portable // code was adapted from, and is substantially faster than math/big. // // The math/big implementation in curve.go is kept for two jobs: signing // arbitrary-length messages as required by the full BIP-340 vector suite, and // cross-checking the fast path in tests. Both implementations are exercised // against each other there. import ( "git.smesh.lol/torly/pkg/crypto/btcec" "git.smesh.lol/torly/pkg/crypto/btcec/schnorr" ) // verifyFast verifies a BIP-340 signature over a 32-byte message. func verifyFast(pub [32]byte, msg [32]byte, sig [64]byte) bool { pk, err := schnorr.ParsePubKey(pub[:]) if err != nil { return false } s, err := schnorr.ParseSignature(sig[:]) if err != nil { return false } return s.Verify(msg[:], pk) } // signFastWithAux signs a 32-byte message with an explicit BIP-340 aux_rand, // which is what the official vectors pin down. func signFastWithAux(sk [32]byte, msg [32]byte, aux [32]byte) ([64]byte, bool) { var out [64]byte priv, _ := btcec.PrivKeyFromBytes(sk[:]) if priv == nil { return out, false } sig, err := schnorr.Sign(priv, msg[:], schnorr.CustomNonce(aux)) if err != nil { return out, false } serialized := sig.Serialize() if len(serialized) != 64 { return out, false } copy(out[:], serialized) var pub [32]byte copy(pub[:], schnorr.SerializePubKey(priv.PubKey())) if !verifyFast(pub, msg, out) { return out, false } return out, true }