github.com/mavryk-network/mvgo@v1.19.9/examples/key/main.go (about)

     1  // Copyright (c) 2020-2021 Blockwatch Data Inc.
     2  // Author: alex@blockwatch.cc
     3  
     4  // Key examples
     5  //
     6  // # Private Keys
     7  // mv1: edsk3nM41ygNfSxVU4w1uAW3G9EnTQEB5rjojeZedLTGmiGRcierVv
     8  // mv2: spsk1zkqrmst1yg2c4xi3crWcZPqgdc9KtPtb9SAZWYHAdiQzdHy7j
     9  // mv3: p2sk3PM77YMR99AvD3fSSxeLChMdiQ6kkEzqoPuSwQqhPsh29irGLC
    10  //
    11  // # Encrypted keys (pw: foo)
    12  // mv1: edesk1uiM6BaysskGto8pRtzKQqFqsy1sea1QRjTzaQYuBxYNhuN6eqEU78TGRXZocsVRJYcN7AaU9JDykwUd8KW
    13  // mv2: spesk246GnDVaqGoYZvKbjrWM1g6xUXnyETXtwZgEYFnP8BQXcaS4rfQQco7C94D1yBmcL1v46Sqy8fXrhBSM7TW
    14  // mv3: p2esk27ocLPLp1JkTWfxByXysGyB7MBDURYJAzAGJLR3XSEV9Nq8wFFdDVXVTwvCwR7Ne2dcUveamjXbvZf3on6T
    15  //
    16  // # Signatures
    17  // edsigtzLBGCyadERX1QsYHKpwnxSxEYQeGLnJGsSkHEsyY8vB5GcNdnvzUZDdFevJK7YZQ2ujwVjvQZn62ahCEcy74AwtbA8HuN
    18  // spsig1RriZtYADyRhyNoQMa6AiPuJJ7AUDcrxWZfgqexzgANqMv4nXs6qsXDoXcoChBgmCcn2t7Y3EkJaVRuAmNh2cDDxWTdmsz
    19  // sigUdRdXYCXW14xqT8mFTMkX4wSmDMBmcW1Vuz1vanGWqYTmuBodueUHGPUsbxgn73AroNwpEBHwPdhXUswzmvCzquiqtcHC
    20  
    21  package main
    22  
    23  import (
    24  	"encoding/hex"
    25  	"flag"
    26  	"fmt"
    27  	"log"
    28  	"os"
    29  	"strings"
    30  	"syscall"
    31  
    32  	"github.com/mavryk-network/mvgo/mavryk"
    33  	"golang.org/x/term"
    34  )
    35  
    36  var (
    37  	flags    = flag.NewFlagSet("key", flag.ContinueOnError)
    38  	verbose  bool
    39  	password string
    40  )
    41  
    42  func init() {
    43  	flags.Usage = func() {}
    44  	flags.BoolVar(&verbose, "v", false, "be verbose")
    45  	flags.StringVar(&password, "password", "", "password for encrypted keys (may also use env TEZOS_KEY_PASSPHRASE)")
    46  }
    47  
    48  func main() {
    49  	if err := flags.Parse(os.Args[1:]); err != nil {
    50  		if err == flag.ErrHelp {
    51  			fmt.Println("Usage: key <cmd> [args]")
    52  			fmt.Println("\nCommands")
    53  			fmt.Printf("  gen <type>                           generate a new key of type\n")
    54  			fmt.Printf("                                         normal: edsk [mv1], spsk [mv2], p2sk [mv3]\n")
    55  			fmt.Printf("                                         encrypted: edesk, spesk, p2esk\n")
    56  			fmt.Printf("  info <key>                           prints info about `key`\n")
    57  			fmt.Printf("  encrypt <key>                        encrypt private `key`\n")
    58  			fmt.Printf("  sign <sk> <msg> [generic]            sign blake2b hash of message `msg` with key\n")
    59  			fmt.Printf("                                         outputs typed signature by default\n")
    60  			fmt.Printf("                                         use `generic` to create a generic signature\n")
    61  			fmt.Printf("  sign-digest <sk> <digest> [generic]  sign blake2b digest with key\n")
    62  			fmt.Printf("                                         outputs typed signature by default\n")
    63  			fmt.Printf("                                         use `generic` to create a generic signature\n")
    64  			fmt.Printf("  verify <pk> <sig> <msg>              verify signature `sig` using pubkey `pk` against blake2b hash of message `msg`\n")
    65  			flags.PrintDefaults()
    66  			os.Exit(0)
    67  		}
    68  		log.Fatalln("Error:", err)
    69  	}
    70  
    71  	if err := run(); err != nil {
    72  		log.Fatalln("Error:", err)
    73  	}
    74  }
    75  
    76  func run() error {
    77  	n := flags.NArg()
    78  	if n < 1 {
    79  		return fmt.Errorf("Command required")
    80  	}
    81  	switch cmd := flags.Arg(0); cmd {
    82  	case "info":
    83  		if n != 2 {
    84  			return fmt.Errorf("Missing key")
    85  		}
    86  		return info(flags.Arg(1))
    87  	case "gen":
    88  		if n != 2 {
    89  			return fmt.Errorf("Missing key type")
    90  		}
    91  		return gen(flags.Arg(1))
    92  	case "encrypt":
    93  		if n != 2 {
    94  			return fmt.Errorf("Missing key")
    95  		}
    96  		return encrypt(flags.Arg(1))
    97  	case "sign":
    98  		if n < 3 {
    99  			return fmt.Errorf("Missing arguments")
   100  		}
   101  		generic := n == 4 && flags.Arg(3) == "generic"
   102  		return sign(flags.Arg(1), flags.Arg(2), generic)
   103  	case "sign-digest":
   104  		if n < 3 {
   105  			return fmt.Errorf("Missing arguments")
   106  		}
   107  		generic := n == 4 && flags.Arg(3) == "generic"
   108  		return signDigest(flags.Arg(1), flags.Arg(2), generic)
   109  	case "verify":
   110  		if n < 4 {
   111  			return fmt.Errorf("Missing arguments")
   112  		}
   113  		return verify(flags.Arg(1), flags.Arg(2), flags.Arg(3))
   114  	default:
   115  		return fmt.Errorf("Unknown command %q", cmd)
   116  	}
   117  }
   118  
   119  func readPassword() mavryk.PassphraseFunc {
   120  	pwd := password
   121  	source := "command line"
   122  	if pwd == "" {
   123  		pwd = os.Getenv("TEZOS_KEY_PASSPHRASE")
   124  		source = "env TEZOS_KEY_PASSPHRASE"
   125  	}
   126  
   127  	if pwd != "" {
   128  		fmt.Printf("Using password from %s %s", source, strings.Repeat("*", len(pwd)))
   129  		return func() ([]byte, error) { return []byte(pwd), nil }
   130  	} else {
   131  		return func() ([]byte, error) {
   132  			fmt.Print("Enter Password: ")
   133  			buf, err := term.ReadPassword(int(syscall.Stdin))
   134  			fmt.Println()
   135  			return buf, err
   136  		}
   137  	}
   138  }
   139  
   140  func info(val string) error {
   141  	if mavryk.IsPrivateKey(val) {
   142  		var (
   143  			sk  mavryk.PrivateKey
   144  			err error
   145  		)
   146  		if mavryk.IsEncryptedKey(val) {
   147  			sk, err = mavryk.ParseEncryptedPrivateKey(val, readPassword())
   148  		} else {
   149  			sk, err = mavryk.ParsePrivateKey(val)
   150  		}
   151  		if err != nil {
   152  			return err
   153  		}
   154  		if !sk.IsValid() {
   155  			return fmt.Errorf("Invalid private key")
   156  		}
   157  
   158  		pk := sk.Public()
   159  		if !pk.IsValid() {
   160  			return fmt.Errorf("Invalid public key")
   161  		}
   162  
   163  		fmt.Printf("Key Type         %s\n", sk.Type)
   164  		fmt.Printf("Private Key      %s\n", sk)
   165  		fmt.Printf("Public Key       %s\n", pk)
   166  		fmt.Printf("Address          %s\n", pk.Address())
   167  		fmt.Printf("Private Key Hex  %x (%d)\n", sk.Data, len(sk.Data))
   168  		fmt.Printf("Public Key Hex   %x (%d)\n", pk.Data, len(pk.Data))
   169  	} else if mavryk.IsPublicKey(val) {
   170  		pk, err := mavryk.ParseKey(val)
   171  		if err != nil {
   172  			return err
   173  		}
   174  		if !pk.IsValid() {
   175  			return fmt.Errorf("Invalid public key")
   176  		}
   177  		fmt.Printf("Key Type         %s\n", pk.Type)
   178  		fmt.Printf("Public Key       %s\n", pk)
   179  		fmt.Printf("Public Key Hex   %x (%d)\n", pk.Data, len(pk.Data))
   180  		fmt.Printf("Address          %s\n", pk.Address())
   181  	} else if mavryk.IsSignature(val) {
   182  		sig, err := mavryk.ParseSignature(val)
   183  		if err != nil {
   184  			return err
   185  		}
   186  		if !sig.IsValid() {
   187  			return fmt.Errorf("Invalid signature")
   188  		}
   189  		fmt.Printf("Sig Type  %s\n", sig.Type)
   190  		fmt.Printf("Sig Hex   %x (%d)\n", sig.Data, len(sig.Data))
   191  
   192  	}
   193  	return nil
   194  }
   195  
   196  func gen(val string) error {
   197  	if !mavryk.IsPrivateKey(val) {
   198  		return fmt.Errorf("unsupported private key type")
   199  	}
   200  
   201  	typ, doEncrypt := mavryk.ParseKeyType(val)
   202  	if !typ.IsValid() {
   203  		return fmt.Errorf("invalid private key type")
   204  	}
   205  
   206  	sk, err := mavryk.GenerateKey(typ)
   207  	if err != nil {
   208  		return err
   209  	}
   210  	pk := sk.Public()
   211  
   212  	fmt.Printf("Key Type         %s\n", sk.Type.SkPrefix())
   213  	fmt.Printf("Private Key      %s\n", sk)
   214  	fmt.Printf("Public Key       %s\n", pk)
   215  	fmt.Printf("Address          %s\n", pk.Address())
   216  	fmt.Printf("Private Key Hex  %x (%d)\n", sk.Data, len(sk.Data))
   217  	fmt.Printf("Public Key Hex   %x (%d)\n", pk.Data, len(pk.Data))
   218  
   219  	if doEncrypt {
   220  		enc, err := sk.Encrypt(readPassword())
   221  		if err != nil {
   222  			return err
   223  		}
   224  		fmt.Printf("Encrypted Key    %s\n", enc)
   225  	}
   226  	return nil
   227  }
   228  
   229  func encrypt(key string) error {
   230  	if !mavryk.IsPrivateKey(key) {
   231  		return fmt.Errorf("private key required")
   232  	}
   233  
   234  	sk, err := mavryk.ParseEncryptedPrivateKey(key, readPassword())
   235  	if err != nil {
   236  		return err
   237  	}
   238  	pk := sk.Public()
   239  
   240  	fmt.Printf("Key Type         %s\n", sk.Type.SkPrefix())
   241  	fmt.Printf("Private Key      %s\n", sk)
   242  	fmt.Printf("Public Key       %s\n", pk)
   243  	fmt.Printf("Address          %s\n", pk.Address())
   244  	fmt.Printf("Private Key Hex  %x (%d)\n", sk.Data, len(sk.Data))
   245  	fmt.Printf("Public Key Hex   %x (%d)\n", pk.Data, len(pk.Data))
   246  
   247  	enc, err := sk.Encrypt(readPassword())
   248  	if err != nil {
   249  		return err
   250  	}
   251  	fmt.Printf("Encrypted Key    %s\n", enc)
   252  	return nil
   253  }
   254  
   255  func sign(key, msg string, generic bool) error {
   256  	sk, err := mavryk.ParseEncryptedPrivateKey(key, readPassword())
   257  	if err != nil {
   258  		return err
   259  	}
   260  	pk := sk.Public()
   261  	digest := mavryk.Digest([]byte(msg))
   262  	sig, err := sk.Sign(digest[:])
   263  	if err != nil {
   264  		return err
   265  	}
   266  
   267  	fmt.Printf("Key Type         %s\n", sk.Type)
   268  	fmt.Printf("Private Key      %s\n", sk)
   269  	fmt.Printf("Public Key       %s\n", pk)
   270  	fmt.Printf("Address          %s\n", pk.Address())
   271  	fmt.Printf("Msg digest       %x\n", digest[:])
   272  	fmt.Printf("Signature        %s\n", sig)
   273  	fmt.Printf("Signature Hex    %x\n", sig.Data)
   274  	if generic {
   275  		fmt.Printf("Generic Sig      %s\n", sig.Generic())
   276  	}
   277  	return nil
   278  }
   279  
   280  func signDigest(key, dgst string, generic bool) error {
   281  	sk, err := mavryk.ParseEncryptedPrivateKey(key, readPassword())
   282  	if err != nil {
   283  		return err
   284  	}
   285  	pk := sk.Public()
   286  	digest, err := hex.DecodeString(dgst)
   287  	if err != nil {
   288  		return err
   289  	}
   290  	sig, err := sk.Sign(digest[:])
   291  	if err != nil {
   292  		return err
   293  	}
   294  
   295  	fmt.Printf("Key Type         %s\n", sk.Type)
   296  	fmt.Printf("Private Key      %s\n", sk)
   297  	fmt.Printf("Public Key       %s\n", pk)
   298  	fmt.Printf("Address          %s\n", pk.Address())
   299  	fmt.Printf("Msg digest       %x\n", digest[:])
   300  	fmt.Printf("Signature        %s\n", sig)
   301  	fmt.Printf("Signature Hex    %x\n", sig.Bytes())
   302  	if generic {
   303  		fmt.Printf("Generic Sig      %s\n", sig.Generic())
   304  	}
   305  	return nil
   306  }
   307  func verify(key, sig, msg string) error {
   308  	pk, err := mavryk.ParseKey(key)
   309  	if err != nil {
   310  		return err
   311  	}
   312  	s, err := mavryk.ParseSignature(sig)
   313  	if err != nil {
   314  		return err
   315  	}
   316  	m := []byte(msg)
   317  	if strings.HasPrefix(msg, "0x") {
   318  		m, err = hex.DecodeString(msg)
   319  		if err != nil {
   320  			return err
   321  		}
   322  	}
   323  	digest := mavryk.Digest([]byte(m))
   324  	if err := pk.Verify(digest[:], s); err == nil {
   325  		fmt.Println("Signature OK")
   326  	} else {
   327  		return err
   328  	}
   329  	return nil
   330  }