github.com/bytom/bytom@v1.1.2-0.20221014091027-bbcba3df6075/blockchain/signers/signers.go (about) 1 // Package signers associates signers and their corresponding keys. 2 package signers 3 4 import ( 5 "bytes" 6 "encoding/binary" 7 "github.com/bytom/bytom/crypto/ed25519/chainkd" 8 "github.com/bytom/bytom/errors" 9 ) 10 11 type keySpace byte 12 13 const ( 14 AssetKeySpace keySpace = 0 15 AccountKeySpace keySpace = 1 16 ) 17 18 const ( 19 //BIP0032 compatible previous derivation rule m/account/address_index 20 BIP0032 uint8 = iota 21 //BIP0032 path derivation rule m/purpose'/coin_type'/account'/change/address_index 22 BIP0044 23 ) 24 25 var ( 26 // ErrBadQuorum is returned by Create when the quorum 27 // provided is less than 1 or greater than the number 28 // of xpubs provided. 29 ErrBadQuorum = errors.New("quorum must be greater than or equal to 1, and must be less than or equal to the length of xpubs") 30 31 // ErrBadXPub is returned by Create when the xpub 32 // provided isn't valid. 33 ErrBadXPub = errors.New("invalid xpub format") 34 35 // ErrNoXPubs is returned by create when the xpubs 36 // slice provided is empty. 37 ErrNoXPubs = errors.New("at least one xpub is required") 38 39 // ErrDupeXPub is returned by create when the same xpub 40 // appears twice in a single call. 41 ErrDupeXPub = errors.New("xpubs cannot contain the same key more than once") 42 ErrDeriveRule = errors.New("invalid key derive rule") 43 ) 44 45 var ( 46 // BIP44Purpose purpose field 0x0000002c little-endian mode. 47 BIP44Purpose = []byte{0x2C, 0x00, 0x00, 0x00} 48 // BTMCoinType coin type field 0x00000099 little-endian mode. 49 BTMCoinType = []byte{0x99, 0x00, 0x00, 0x00} 50 ) 51 52 // Signer is the abstract concept of a signer, 53 // which is composed of a set of keys as well as 54 // the amount of signatures needed for quorum. 55 type Signer struct { 56 Type string `json:"type"` 57 XPubs []chainkd.XPub `json:"xpubs"` 58 Quorum int `json:"quorum"` 59 KeyIndex uint64 `json:"key_index"` 60 DeriveRule uint8 `json:"derive_rule"` 61 } 62 63 // GetBip0032Path returns the complete path for bip0032 derived keys 64 func GetBip0032Path(s *Signer, ks keySpace, itemIndexes ...uint64) [][]byte { 65 var path [][]byte 66 signerPath := [9]byte{byte(ks)} 67 binary.LittleEndian.PutUint64(signerPath[1:], s.KeyIndex) 68 path = append(path, signerPath[:]) 69 for _, idx := range itemIndexes { 70 var idxBytes [8]byte 71 binary.LittleEndian.PutUint64(idxBytes[:], idx) 72 path = append(path, idxBytes[:]) 73 } 74 return path 75 } 76 77 // getBip0044Path returns the complete path for bip0044 derived keys 78 func getBip0044Path(accountIndex uint64, change bool, addrIndex uint64) [][]byte { 79 var path [][]byte 80 path = append(path, BIP44Purpose[:]) //purpose 81 path = append(path, BTMCoinType[:]) //coin type 82 accIdxBytes := make([]byte, 4) 83 binary.LittleEndian.PutUint32(accIdxBytes, uint32(accountIndex)) 84 path = append(path, accIdxBytes) //account index 85 branchBytes := make([]byte, 4) 86 if change { 87 binary.LittleEndian.PutUint32(branchBytes, uint32(1)) 88 } else { 89 binary.LittleEndian.PutUint32(branchBytes, uint32(0)) 90 } 91 path = append(path, branchBytes) //change 92 addrIdxBytes := make([]byte, 4) 93 binary.LittleEndian.PutUint32(addrIdxBytes[:], uint32(addrIndex)) 94 path = append(path, addrIdxBytes[:]) //address index 95 return path 96 } 97 98 // Path returns the complete path for derived keys 99 func Path(s *Signer, ks keySpace, change bool, addrIndex uint64) ([][]byte, error) { 100 switch s.DeriveRule { 101 case BIP0032: 102 return GetBip0032Path(s, ks, addrIndex), nil 103 case BIP0044: 104 return getBip0044Path(s.KeyIndex, change, addrIndex), nil 105 } 106 return nil, ErrDeriveRule 107 } 108 109 // Create creates and stores a Signer in the database 110 func Create(signerType string, xpubs []chainkd.XPub, quorum int, keyIndex uint64, deriveRule uint8) (*Signer, error) { 111 if len(xpubs) == 0 { 112 return nil, errors.Wrap(ErrNoXPubs) 113 } 114 115 xpubsMap := map[chainkd.XPub]bool{} 116 for _, xpub := range xpubs { 117 if _, ok := xpubsMap[xpub]; ok { 118 return nil, errors.WithDetailf(ErrDupeXPub, "duplicated key=%x", xpub) 119 } 120 xpubsMap[xpub] = true 121 } 122 123 if quorum == 0 || quorum > len(xpubs) { 124 return nil, errors.Wrap(ErrBadQuorum) 125 } 126 127 return &Signer{ 128 Type: signerType, 129 XPubs: xpubs, 130 Quorum: quorum, 131 KeyIndex: keyIndex, 132 DeriveRule: deriveRule, 133 }, nil 134 } 135 136 type SortKeys []chainkd.XPub 137 138 func (s SortKeys) Len() int { return len(s) } 139 func (s SortKeys) Less(i, j int) bool { return bytes.Compare(s[i][:], s[j][:]) < 0 } 140 func (s SortKeys) Swap(i, j int) { s[i], s[j] = s[j], s[i] }