forked from decred/dcrd
-
Notifications
You must be signed in to change notification settings - Fork 0
/
util.go
97 lines (82 loc) · 3.23 KB
/
util.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
// Copyright (c) 2013, 2014 The btcsuite developers
// Copyright (c) 2015-2023 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package dcrutil
import (
"bytes"
"encoding/base64"
"fmt"
"github.com/sebitt27/dcrd/chaincfg/chainhash"
"github.com/sebitt27/dcrd/dcrec/secp256k1/v4/ecdsa"
"github.com/sebitt27/dcrd/txscript/v4/stdaddr"
"github.com/sebitt27/dcrd/wire"
)
// AddressParams defines an interface that is used to provide the parameters
// required when encoding and decoding addresses. These values are typically
// well-defined and unique per network.
type AddressParams interface {
// AddrIDPubKeyV0 returns the magic prefix bytes for version 0 pay-to-pubkey
// addresses.
AddrIDPubKeyV0() [2]byte
// AddrIDPubKeyHashECDSAV0 returns the magic prefix bytes for version 0
// pay-to-pubkey-hash addresses where the underlying pubkey is secp256k1 and
// the signature algorithm is ECDSA.
AddrIDPubKeyHashECDSAV0() [2]byte
// AddrIDPubKeyHashEd25519V0 returns the magic prefix bytes for version 0
// pay-to-pubkey-hash addresses where the underlying pubkey and signature
// algorithm are Ed25519.
AddrIDPubKeyHashEd25519V0() [2]byte
// AddrIDPubKeyHashSchnorrV0 returns the magic prefix bytes for version 0
// pay-to-pubkey-hash addresses where the underlying pubkey is secp256k1 and
// the signature algorithm is Schnorr.
AddrIDPubKeyHashSchnorrV0() [2]byte
// AddrIDScriptHashV0 returns the magic prefix bytes for version 0
// pay-to-script-hash addresses.
AddrIDScriptHashV0() [2]byte
}
// VerifyMessage verifies that signature is a valid signature of message and was created
// using the secp256k1 private key for address.
func VerifyMessage(address string, signature string, message string, params AddressParams) error {
// Decode the provided address. This also ensures the network encoded with
// the address matches the network the server is currently on.
addr, err := stdaddr.DecodeAddress(address, params)
if err != nil {
return err
}
// Only P2PKH addresses are valid for signing.
if _, ok := addr.(*stdaddr.AddressPubKeyHashEcdsaSecp256k1V0); !ok {
return fmt.Errorf("address is not a pay-to-pubkey-hash address")
}
// Decode base64 signature.
sig, err := base64.StdEncoding.DecodeString(signature)
if err != nil {
return fmt.Errorf("malformed base64 encoding: %w", err)
}
// Validate the signature - this just shows that it was valid for any pubkey
// at all. Whether the pubkey matches is checked below.
var buf bytes.Buffer
wire.WriteVarString(&buf, 0, "Decred Signed Message:\n")
wire.WriteVarString(&buf, 0, message)
expectedMessageHash := chainhash.HashB(buf.Bytes())
pk, wasCompressed, err := ecdsa.RecoverCompact(sig, expectedMessageHash)
if err != nil {
return err
}
// Reconstruct the address from the recovered pubkey.
var pkHash []byte
if wasCompressed {
pkHash = stdaddr.Hash160(pk.SerializeCompressed())
} else {
pkHash = stdaddr.Hash160(pk.SerializeUncompressed())
}
recAddr, err := stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0(pkHash, params)
if err != nil {
return err
}
// Check whether addresses match.
if recAddr.String() != addr.String() {
return fmt.Errorf("message not signed by address")
}
return nil
}