1 package secp256k1
2 3 // The hot path is verification, and for 32-byte messages (the only length
4 // Nostr uses) it is delegated to btcec's BIP-340 implementation. That package
5 // carries the same pure-Go 5x52/10x26 field arithmetic that orly's portable
6 // code was adapted from, and is substantially faster than math/big.
7 //
8 // The math/big implementation in curve.go is kept for two jobs: signing
9 // arbitrary-length messages as required by the full BIP-340 vector suite, and
10 // cross-checking the fast path in tests. Both implementations are exercised
11 // against each other there.
12 13 import (
14 "git.smesh.lol/torly/pkg/crypto/btcec"
15 "git.smesh.lol/torly/pkg/crypto/btcec/schnorr"
16 )
17 18 // verifyFast verifies a BIP-340 signature over a 32-byte message.
19 func verifyFast(pub [32]byte, msg [32]byte, sig [64]byte) bool {
20 pk, err := schnorr.ParsePubKey(pub[:])
21 if err != nil {
22 return false
23 }
24 s, err := schnorr.ParseSignature(sig[:])
25 if err != nil {
26 return false
27 }
28 return s.Verify(msg[:], pk)
29 }
30 31 // signFastWithAux signs a 32-byte message with an explicit BIP-340 aux_rand,
32 // which is what the official vectors pin down.
33 func signFastWithAux(sk [32]byte, msg [32]byte, aux [32]byte) ([64]byte, bool) {
34 var out [64]byte
35 priv, _ := btcec.PrivKeyFromBytes(sk[:])
36 if priv == nil {
37 return out, false
38 }
39 sig, err := schnorr.Sign(priv, msg[:], schnorr.CustomNonce(aux))
40 if err != nil {
41 return out, false
42 }
43 serialized := sig.Serialize()
44 if len(serialized) != 64 {
45 return out, false
46 }
47 copy(out[:], serialized)
48 var pub [32]byte
49 copy(pub[:], schnorr.SerializePubKey(priv.PubKey()))
50 if !verifyFast(pub, msg, out) {
51 return out, false
52 }
53 return out, true
54 }
55