github.com/piotrnar/gocoin@v0.0.0-20240512203912-faa0448c5e96/tools/btcversig/btcversig.go (about) 1 // This tool is able to verify whether a message was signed with the given bitcoin address 2 package main 3 4 import ( 5 "bytes" 6 "flag" 7 "fmt" 8 "io/ioutil" 9 "os" 10 11 "github.com/piotrnar/gocoin/lib/btc" 12 "github.com/piotrnar/gocoin/lib/others/ltc" 13 ) 14 15 var ( 16 addr = flag.String("a", "", "base58 encoded bitcoin address that supposedly signed the message (required)") 17 sign = flag.String("s", "", "base64 encoded signature of the message (required)") 18 mess = flag.String("m", "", "the message (optional)") 19 mfil = flag.String("f", "", "the filename containing a signed message (optional)") 20 unix = flag.Bool("u", false, "remove all \\r characters from the message (optional)") 21 help = flag.Bool("h", false, "print this help") 22 verb = flag.Bool("v", false, "verbose mode") 23 litecoin = flag.Bool("ltc", false, "litecoin mode") 24 ) 25 26 func main() { 27 var msg []byte 28 29 flag.Parse() 30 31 if *help || *addr == "" || *sign == "" { 32 flag.PrintDefaults() 33 return 34 } 35 36 ad, er := btc.NewAddrFromString(*addr) 37 if !*litecoin && ad != nil && ad.Version == ltc.AddrVerPubkey(false) { 38 *litecoin = true 39 } 40 if er != nil { 41 println("Address:", er.Error()) 42 flag.PrintDefaults() 43 return 44 } 45 if ad.SegwitProg != nil && len(ad.SegwitProg.Program) == 20 { 46 copy(ad.Hash160[:], ad.SegwitProg.Program) 47 } 48 49 nv, btcsig, er := btc.ParseMessageSignature(*sign) 50 if er != nil { 51 println("ParseMessageSignature:", er.Error()) 52 return 53 } 54 55 if *mess != "" { 56 msg = []byte(*mess) 57 } else if *mfil != "" { 58 msg, er = ioutil.ReadFile(*mfil) 59 if er != nil { 60 println(er.Error()) 61 return 62 } 63 } else { 64 if *verb { 65 fmt.Println("Enter the message:") 66 } 67 msg, _ = ioutil.ReadAll(os.Stdin) 68 } 69 70 if *unix { 71 if *verb { 72 fmt.Println("Enforcing Unix text format") 73 } 74 msg = bytes.Replace(msg, []byte{'\r'}, nil, -1) 75 } 76 77 hash := make([]byte, 32) 78 if *litecoin { 79 ltc.HashFromMessage(msg, hash) 80 } else { 81 btc.HashFromMessage(msg, hash) 82 } 83 84 compressed := false 85 if nv >= 31 { 86 if *verb { 87 fmt.Println("compressed key") 88 } 89 nv -= 4 90 compressed = true 91 } 92 93 pub := btcsig.RecoverPublicKey(hash[:], int(nv-27)) 94 if pub != nil { 95 pk := pub.Bytes(compressed) 96 ok := btc.EcdsaVerify(pk, btcsig.Bytes(), hash) 97 if ok { 98 sa := btc.NewAddrFromPubkey(pk, ad.Version) 99 if ad.Version == btc.AddrVerScript(true) || ad.Version == btc.AddrVerScript(false) { 100 // a trick to make the segwit P2SH addresses to work 101 tmp := btc.Rimp160AfterSha256(append([]byte{0, 20}, sa.Hash160[:]...)) 102 copy(sa.Hash160[:], tmp[:]) 103 } 104 if ad.Hash160 != sa.Hash160 { 105 fmt.Println("BAD signature for", ad.String()) 106 if bytes.IndexByte(msg, '\r') != -1 { 107 fmt.Println("You have CR chars in the message. Try to verify with -u switch.") 108 } 109 os.Exit(1) 110 } else { 111 fmt.Println("Signature OK") 112 } 113 } else { 114 println("BAD signature") 115 os.Exit(1) 116 } 117 } else { 118 println("BAD, BAD, BAD signature") 119 os.Exit(1) 120 } 121 }