mirror of
https://github.com/fiatjaf/nak.git
synced 2024-10-30 00:59:07 -04:00
parent
85e9610265
commit
9d43e66fac
|
@ -194,6 +194,12 @@ listening at [wss://relay.damus.io wss://nos.lol wss://relay.nsecbunker.com]:
|
||||||
• events stored: 4, subscriptions opened: 1
|
• events stored: 4, subscriptions opened: 1
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### make an event with a PoW target
|
||||||
|
```shell
|
||||||
|
~> nak event -c 'hello getwired.app and labour.fiatjaf.com' --pow 24
|
||||||
|
{"kind":1,"id":"0000009dcc7c62056eafdb41fac817379ec2becf0ce27c5fbe98d0735d968147","pubkey":"79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798","created_at":1724160828,"tags":[["nonce","515504","24"]],"content":"hello getwired.app and labour.fiatjaf.com","sig":"7edb988065ccc12779fe99270945b212f3723838f315d76d5e90e9ffa27198f13fa556614295f518d968d55bab81878167d4162b3a7cf81a6b423c6761bd504c"}
|
||||||
|
```
|
||||||
|
|
||||||
## contributing to this repository
|
## contributing to this repository
|
||||||
|
|
||||||
Use NIP-34 to send your patches to `naddr1qqpkucttqy28wumn8ghj7un9d3shjtnwdaehgu3wvfnsz9nhwden5te0wfjkccte9ehx7um5wghxyctwvsq3gamnwvaz7tmjv4kxz7fwv3sk6atn9e5k7q3q80cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkwsxpqqqpmej2wctpn`.
|
Use NIP-34 to send your patches to `naddr1qqpkucttqy28wumn8ghj7un9d3shjtnwdaehgu3wvfnsz9nhwden5te0wfjkccte9ehx7um5wghxyctwvsq3gamnwvaz7tmjv4kxz7fwv3sk6atn9e5k7q3q80cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkwsxpqqqpmej2wctpn`.
|
||||||
|
|
77
event.go
77
event.go
|
@ -11,11 +11,16 @@ import (
|
||||||
"github.com/fiatjaf/cli/v3"
|
"github.com/fiatjaf/cli/v3"
|
||||||
"github.com/mailru/easyjson"
|
"github.com/mailru/easyjson"
|
||||||
"github.com/nbd-wtf/go-nostr"
|
"github.com/nbd-wtf/go-nostr"
|
||||||
|
"github.com/nbd-wtf/go-nostr/nip13"
|
||||||
"github.com/nbd-wtf/go-nostr/nip19"
|
"github.com/nbd-wtf/go-nostr/nip19"
|
||||||
"golang.org/x/exp/slices"
|
"golang.org/x/exp/slices"
|
||||||
)
|
)
|
||||||
|
|
||||||
const CATEGORY_EVENT_FIELDS = "EVENT FIELDS"
|
const (
|
||||||
|
CATEGORY_EVENT_FIELDS = "EVENT FIELDS"
|
||||||
|
CATEGORY_SIGNER = "SIGNER OPTIONS"
|
||||||
|
CATEGORY_EXTRAS = "EXTRAS"
|
||||||
|
)
|
||||||
|
|
||||||
var event = &cli.Command{
|
var event = &cli.Command{
|
||||||
Name: "event",
|
Name: "event",
|
||||||
|
@ -38,19 +43,23 @@ example:
|
||||||
Usage: "secret key to sign the event, as nsec, ncryptsec or hex",
|
Usage: "secret key to sign the event, as nsec, ncryptsec or hex",
|
||||||
DefaultText: "the key '1'",
|
DefaultText: "the key '1'",
|
||||||
Value: "0000000000000000000000000000000000000000000000000000000000000001",
|
Value: "0000000000000000000000000000000000000000000000000000000000000001",
|
||||||
|
Category: CATEGORY_SIGNER,
|
||||||
},
|
},
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "prompt-sec",
|
Name: "prompt-sec",
|
||||||
Usage: "prompt the user to paste a hex or nsec with which to sign the event",
|
Usage: "prompt the user to paste a hex or nsec with which to sign the event",
|
||||||
|
Category: CATEGORY_SIGNER,
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "connect",
|
Name: "connect",
|
||||||
Usage: "sign event using NIP-46, expects a bunker://... URL",
|
Usage: "sign event using NIP-46, expects a bunker://... URL",
|
||||||
|
Category: CATEGORY_SIGNER,
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "connect-as",
|
Name: "connect-as",
|
||||||
Usage: "private key to when communicating with the bunker given on --connect",
|
Usage: "private key to when communicating with the bunker given on --connect",
|
||||||
DefaultText: "a random key",
|
DefaultText: "a random key",
|
||||||
|
Category: CATEGORY_SIGNER,
|
||||||
},
|
},
|
||||||
// ~ these args are only for the convoluted musig2 signing process
|
// ~ these args are only for the convoluted musig2 signing process
|
||||||
// they will be generally copy-shared-pasted across some manual coordination method between participants
|
// they will be generally copy-shared-pasted across some manual coordination method between participants
|
||||||
|
@ -59,6 +68,7 @@ example:
|
||||||
Usage: "number of signers to use for musig2",
|
Usage: "number of signers to use for musig2",
|
||||||
Value: 1,
|
Value: 1,
|
||||||
DefaultText: "1 -- i.e. do not use musig2 at all",
|
DefaultText: "1 -- i.e. do not use musig2 at all",
|
||||||
|
Category: CATEGORY_SIGNER,
|
||||||
},
|
},
|
||||||
&cli.StringSliceFlag{
|
&cli.StringSliceFlag{
|
||||||
Name: "musig-pubkey",
|
Name: "musig-pubkey",
|
||||||
|
@ -77,17 +87,25 @@ example:
|
||||||
Hidden: true,
|
Hidden: true,
|
||||||
},
|
},
|
||||||
// ~~~
|
// ~~~
|
||||||
&cli.BoolFlag{
|
&cli.UintFlag{
|
||||||
Name: "envelope",
|
Name: "pow",
|
||||||
Usage: "print the event enveloped in a [\"EVENT\", ...] message ready to be sent to a relay",
|
Usage: "NIP-13 difficulty to target when doing hash work on the event id",
|
||||||
|
Category: CATEGORY_EXTRAS,
|
||||||
},
|
},
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "auth",
|
Name: "envelope",
|
||||||
Usage: "always perform NIP-42 \"AUTH\" when facing an \"auth-required: \" rejection and try again",
|
Usage: "print the event enveloped in a [\"EVENT\", ...] message ready to be sent to a relay",
|
||||||
|
Category: CATEGORY_EXTRAS,
|
||||||
},
|
},
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "nevent",
|
Name: "auth",
|
||||||
Usage: "print the nevent code (to stderr) after the event is published",
|
Usage: "always perform NIP-42 \"AUTH\" when facing an \"auth-required: \" rejection and try again",
|
||||||
|
Category: CATEGORY_EXTRAS,
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "nevent",
|
||||||
|
Usage: "print the nevent code (to stderr) after the event is published",
|
||||||
|
Category: CATEGORY_EXTRAS,
|
||||||
},
|
},
|
||||||
&cli.UintFlag{
|
&cli.UintFlag{
|
||||||
Name: "kind",
|
Name: "kind",
|
||||||
|
@ -193,8 +211,9 @@ example:
|
||||||
mustRehashAndResign = true
|
mustRehashAndResign = true
|
||||||
}
|
}
|
||||||
|
|
||||||
tags := make(nostr.Tags, 0, 5)
|
tagFlags := c.StringSlice("tag")
|
||||||
for _, tagFlag := range c.StringSlice("tag") {
|
tags := make(nostr.Tags, 0, len(tagFlags)+2)
|
||||||
|
for _, tagFlag := range tagFlags {
|
||||||
// tags are in the format key=value
|
// tags are in the format key=value
|
||||||
tagName, tagValue, found := strings.Cut(tagFlag, "=")
|
tagName, tagValue, found := strings.Cut(tagFlag, "=")
|
||||||
tag := []string{tagName}
|
tag := []string{tagName}
|
||||||
|
@ -203,20 +222,17 @@ example:
|
||||||
tagValues := strings.Split(tagValue, ";")
|
tagValues := strings.Split(tagValue, ";")
|
||||||
tag = append(tag, tagValues...)
|
tag = append(tag, tagValues...)
|
||||||
}
|
}
|
||||||
tags = tags.AppendUnique(tag)
|
tags = append(tags, tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, etag := range c.StringSlice("e") {
|
for _, etag := range c.StringSlice("e") {
|
||||||
tags = tags.AppendUnique([]string{"e", etag})
|
tags = tags.AppendUnique([]string{"e", etag})
|
||||||
mustRehashAndResign = true
|
|
||||||
}
|
}
|
||||||
for _, ptag := range c.StringSlice("p") {
|
for _, ptag := range c.StringSlice("p") {
|
||||||
tags = tags.AppendUnique([]string{"p", ptag})
|
tags = tags.AppendUnique([]string{"p", ptag})
|
||||||
mustRehashAndResign = true
|
|
||||||
}
|
}
|
||||||
for _, dtag := range c.StringSlice("d") {
|
for _, dtag := range c.StringSlice("d") {
|
||||||
tags = tags.AppendUnique([]string{"d", dtag})
|
tags = tags.AppendUnique([]string{"d", dtag})
|
||||||
mustRehashAndResign = true
|
|
||||||
}
|
}
|
||||||
if len(tags) > 0 {
|
if len(tags) > 0 {
|
||||||
for _, tag := range tags {
|
for _, tag := range tags {
|
||||||
|
@ -233,6 +249,31 @@ example:
|
||||||
mustRehashAndResign = true
|
mustRehashAndResign = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if difficulty := c.Uint("pow"); difficulty > 0 {
|
||||||
|
// before doing pow we need the pubkey
|
||||||
|
if bunker != nil {
|
||||||
|
evt.PubKey, err = bunker.GetPublicKey(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("can't pow: failed to get public key from bunker: %w", err)
|
||||||
|
}
|
||||||
|
} else if numSigners := c.Uint("musig"); numSigners > 1 && sec != "" {
|
||||||
|
pubkeys := c.StringSlice("musig-pubkey")
|
||||||
|
if int(numSigners) != len(pubkeys) {
|
||||||
|
return fmt.Errorf("when doing a pow with musig we must know all signer pubkeys upfront")
|
||||||
|
}
|
||||||
|
evt.PubKey, err = getMusigAggregatedKey(ctx, pubkeys)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
evt.PubKey, _ = nostr.GetPublicKey(sec)
|
||||||
|
}
|
||||||
|
|
||||||
|
// try to generate work with this difficulty -- essentially forever
|
||||||
|
nip13.Generate(&evt, int(difficulty), time.Hour*24*365)
|
||||||
|
mustRehashAndResign = true
|
||||||
|
}
|
||||||
|
|
||||||
if evt.Sig == "" || mustRehashAndResign {
|
if evt.Sig == "" || mustRehashAndResign {
|
||||||
if bunker != nil {
|
if bunker != nil {
|
||||||
if err := bunker.SignEvent(ctx, &evt); err != nil {
|
if err := bunker.SignEvent(ctx, &evt); err != nil {
|
||||||
|
|
25
musig2.go
25
musig2.go
|
@ -15,6 +15,31 @@ import (
|
||||||
"github.com/nbd-wtf/go-nostr"
|
"github.com/nbd-wtf/go-nostr"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func getMusigAggregatedKey(_ context.Context, keys []string) (string, error) {
|
||||||
|
knownSigners := make([]*btcec.PublicKey, len(keys))
|
||||||
|
for i, spk := range keys {
|
||||||
|
bpk, err := hex.DecodeString(spk)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("'%s' is invalid hex: %w", spk, err)
|
||||||
|
}
|
||||||
|
if len(bpk) == 32 {
|
||||||
|
return "", fmt.Errorf("'%s' is missing the leading parity byte", spk)
|
||||||
|
}
|
||||||
|
pk, err := btcec.ParsePubKey(bpk)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("'%s' is not a valid pubkey: %w", spk, err)
|
||||||
|
}
|
||||||
|
knownSigners[i] = pk
|
||||||
|
}
|
||||||
|
|
||||||
|
aggpk, _, _, err := musig2.AggregateKeys(knownSigners, true)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("aggregation failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return hex.EncodeToString(aggpk.FinalKey.SerializeCompressed()[1:]), nil
|
||||||
|
}
|
||||||
|
|
||||||
func performMusig(
|
func performMusig(
|
||||||
_ context.Context,
|
_ context.Context,
|
||||||
sec string,
|
sec string,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user