github.com/Bytom/bytom@v1.1.2-0.20210127130405-ae40204c0b09/crypto/ed25519/chainkd/chainkd.go (about) 1 package chainkd 2 3 import ( 4 "crypto/hmac" 5 "crypto/rand" 6 "crypto/sha512" 7 "io" 8 9 "github.com/bytom/bytom/crypto/ed25519" 10 "github.com/bytom/bytom/crypto/ed25519/ecmath" 11 ) 12 13 type ( 14 //XPrv external private key 15 XPrv [64]byte 16 //XPub external public key 17 XPub [64]byte 18 ) 19 20 // NewXPrv takes a source of random bytes and produces a new XPrv. 21 // If r is nil, crypto/rand.Reader is used. 22 func NewXPrv(r io.Reader) (xprv XPrv, err error) { 23 if r == nil { 24 r = rand.Reader 25 } 26 var entropy [64]byte 27 _, err = io.ReadFull(r, entropy[:]) 28 if err != nil { 29 return xprv, err 30 } 31 return RootXPrv(entropy[:]), nil 32 } 33 34 // RootXPrv takes a seed binary string and produces a new xprv. 35 func RootXPrv(seed []byte) (xprv XPrv) { 36 h := hmac.New(sha512.New, []byte{'R', 'o', 'o', 't'}) 37 h.Write(seed) 38 h.Sum(xprv[:0]) 39 pruneRootScalar(xprv[:32]) 40 return 41 } 42 43 // XPub derives an extended public key from a given xprv. 44 func (xprv XPrv) XPub() (xpub XPub) { 45 var scalar ecmath.Scalar 46 copy(scalar[:], xprv[:32]) 47 48 var P ecmath.Point 49 P.ScMulBase(&scalar) 50 buf := P.Encode() 51 52 copy(xpub[:32], buf[:]) 53 copy(xpub[32:], xprv[32:]) 54 55 return 56 } 57 58 // Child derives a child xprv based on `selector` string and `hardened` flag. 59 // If `hardened` is false, child xpub can be derived independently 60 // from the parent xpub without using the parent xprv. 61 // If `hardened` is true, child key can only be derived from the parent xprv. 62 func (xprv XPrv) Child(sel []byte, hardened bool) XPrv { 63 if hardened { 64 return xprv.hardenedChild(sel) 65 } 66 return xprv.nonhardenedChild(sel) 67 } 68 69 func (xprv XPrv) hardenedChild(sel []byte) (res XPrv) { 70 h := hmac.New(sha512.New, xprv[32:]) 71 h.Write([]byte{'H'}) 72 h.Write(xprv[:32]) 73 h.Write(sel) 74 h.Sum(res[:0]) 75 pruneRootScalar(res[:32]) 76 return 77 } 78 79 func (xprv XPrv) nonhardenedChild(sel []byte) (res XPrv) { 80 xpub := xprv.XPub() 81 82 h := hmac.New(sha512.New, xpub[32:]) 83 h.Write([]byte{'N'}) 84 h.Write(xpub[:32]) 85 h.Write(sel) 86 h.Sum(res[:0]) 87 88 pruneIntermediateScalar(res[:32]) 89 90 // Unrolled the following loop: 91 // var carry int 92 // carry = 0 93 // for i := 0; i < 32; i++ { 94 // sum := int(xprv[i]) + int(res[i]) + carry 95 // res[i] = byte(sum & 0xff) 96 // carry = (sum >> 8) 97 // } 98 99 sum := int(0) 100 101 sum = int(xprv[0]) + int(res[0]) + (sum >> 8) 102 res[0] = byte(sum & 0xff) 103 sum = int(xprv[1]) + int(res[1]) + (sum >> 8) 104 res[1] = byte(sum & 0xff) 105 sum = int(xprv[2]) + int(res[2]) + (sum >> 8) 106 res[2] = byte(sum & 0xff) 107 sum = int(xprv[3]) + int(res[3]) + (sum >> 8) 108 res[3] = byte(sum & 0xff) 109 sum = int(xprv[4]) + int(res[4]) + (sum >> 8) 110 res[4] = byte(sum & 0xff) 111 sum = int(xprv[5]) + int(res[5]) + (sum >> 8) 112 res[5] = byte(sum & 0xff) 113 sum = int(xprv[6]) + int(res[6]) + (sum >> 8) 114 res[6] = byte(sum & 0xff) 115 sum = int(xprv[7]) + int(res[7]) + (sum >> 8) 116 res[7] = byte(sum & 0xff) 117 sum = int(xprv[8]) + int(res[8]) + (sum >> 8) 118 res[8] = byte(sum & 0xff) 119 sum = int(xprv[9]) + int(res[9]) + (sum >> 8) 120 res[9] = byte(sum & 0xff) 121 sum = int(xprv[10]) + int(res[10]) + (sum >> 8) 122 res[10] = byte(sum & 0xff) 123 sum = int(xprv[11]) + int(res[11]) + (sum >> 8) 124 res[11] = byte(sum & 0xff) 125 sum = int(xprv[12]) + int(res[12]) + (sum >> 8) 126 res[12] = byte(sum & 0xff) 127 sum = int(xprv[13]) + int(res[13]) + (sum >> 8) 128 res[13] = byte(sum & 0xff) 129 sum = int(xprv[14]) + int(res[14]) + (sum >> 8) 130 res[14] = byte(sum & 0xff) 131 sum = int(xprv[15]) + int(res[15]) + (sum >> 8) 132 res[15] = byte(sum & 0xff) 133 sum = int(xprv[16]) + int(res[16]) + (sum >> 8) 134 res[16] = byte(sum & 0xff) 135 sum = int(xprv[17]) + int(res[17]) + (sum >> 8) 136 res[17] = byte(sum & 0xff) 137 sum = int(xprv[18]) + int(res[18]) + (sum >> 8) 138 res[18] = byte(sum & 0xff) 139 sum = int(xprv[19]) + int(res[19]) + (sum >> 8) 140 res[19] = byte(sum & 0xff) 141 sum = int(xprv[20]) + int(res[20]) + (sum >> 8) 142 res[20] = byte(sum & 0xff) 143 sum = int(xprv[21]) + int(res[21]) + (sum >> 8) 144 res[21] = byte(sum & 0xff) 145 sum = int(xprv[22]) + int(res[22]) + (sum >> 8) 146 res[22] = byte(sum & 0xff) 147 sum = int(xprv[23]) + int(res[23]) + (sum >> 8) 148 res[23] = byte(sum & 0xff) 149 sum = int(xprv[24]) + int(res[24]) + (sum >> 8) 150 res[24] = byte(sum & 0xff) 151 sum = int(xprv[25]) + int(res[25]) + (sum >> 8) 152 res[25] = byte(sum & 0xff) 153 sum = int(xprv[26]) + int(res[26]) + (sum >> 8) 154 res[26] = byte(sum & 0xff) 155 sum = int(xprv[27]) + int(res[27]) + (sum >> 8) 156 res[27] = byte(sum & 0xff) 157 sum = int(xprv[28]) + int(res[28]) + (sum >> 8) 158 res[28] = byte(sum & 0xff) 159 sum = int(xprv[29]) + int(res[29]) + (sum >> 8) 160 res[29] = byte(sum & 0xff) 161 sum = int(xprv[30]) + int(res[30]) + (sum >> 8) 162 res[30] = byte(sum & 0xff) 163 sum = int(xprv[31]) + int(res[31]) + (sum >> 8) 164 res[31] = byte(sum & 0xff) 165 166 if (sum >> 8) != 0 { 167 panic("sum does not fit in 256-bit int") 168 } 169 return 170 } 171 172 // Child derives a child xpub based on `selector` string. 173 // The corresponding child xprv can be derived from the parent xprv 174 // using non-hardened derivation: `parentxprv.Child(sel, false)`. 175 func (xpub XPub) Child(sel []byte) (res XPub) { 176 h := hmac.New(sha512.New, xpub[32:]) 177 h.Write([]byte{'N'}) 178 h.Write(xpub[:32]) 179 h.Write(sel) 180 h.Sum(res[:0]) 181 182 pruneIntermediateScalar(res[:32]) 183 184 var ( 185 f ecmath.Scalar 186 F ecmath.Point 187 ) 188 copy(f[:], res[:32]) 189 F.ScMulBase(&f) 190 191 var ( 192 pubkey [32]byte 193 P ecmath.Point 194 ) 195 copy(pubkey[:], xpub[:32]) 196 _, ok := P.Decode(pubkey) 197 if !ok { 198 panic("XPub should have been validated on initialization") 199 } 200 201 P.Add(&P, &F) 202 pubkey = P.Encode() 203 copy(res[:32], pubkey[:]) 204 205 return 206 } 207 208 // Derive generates a child xprv by recursively deriving 209 // non-hardened child xprvs over the list of selectors: 210 // `Derive([a,b,c,...]) == Child(a).Child(b).Child(c)...` 211 func (xprv XPrv) Derive(path [][]byte) XPrv { 212 res := xprv 213 for _, p := range path { 214 res = res.Child(p, false) 215 } 216 return res 217 } 218 219 // Derive generates a child xpub by recursively deriving 220 // non-hardened child xpubs over the list of selectors: 221 // `Derive([a,b,c,...]) == Child(a).Child(b).Child(c)...` 222 func (xpub XPub) Derive(path [][]byte) XPub { 223 res := xpub 224 for _, p := range path { 225 res = res.Child(p) 226 } 227 return res 228 } 229 230 // Sign creates an EdDSA signature using expanded private key 231 // derived from the xprv. 232 func (xprv XPrv) Sign(msg []byte) []byte { 233 return Ed25519InnerSign(xprv.ExpandedPrivateKey(), msg) 234 } 235 236 // Verify checks an EdDSA signature using public key 237 // extracted from the first 32 bytes of the xpub. 238 func (xpub XPub) Verify(msg []byte, sig []byte) bool { 239 return ed25519.Verify(xpub.PublicKey(), msg, sig) 240 } 241 242 // ExpandedPrivateKey generates a 64-byte key where 243 // the first half is the scalar copied from xprv, 244 // and the second half is the `prefix` is generated via PRF 245 // from the xprv. 246 func (xprv XPrv) ExpandedPrivateKey() ExpandedPrivateKey { 247 var res [64]byte 248 h := hmac.New(sha512.New, []byte{'E', 'x', 'p', 'a', 'n', 'd'}) 249 h.Write(xprv[:]) 250 h.Sum(res[:0]) 251 copy(res[:32], xprv[:32]) 252 return res[:] 253 } 254 255 // PublicKey extracts the ed25519 public key from an xpub. 256 func (xpub XPub) PublicKey() ed25519.PublicKey { 257 return ed25519.PublicKey(xpub[:32]) 258 } 259 260 // s must be >= 32 bytes long and gets rewritten in place. 261 // This is NOT the same pruning as in Ed25519: it additionally clears the third 262 // highest bit to ensure subkeys do not overflow the second highest bit. 263 func pruneRootScalar(s []byte) { 264 s[0] &= 248 265 s[31] &= 31 // clear top 3 bits 266 s[31] |= 64 // set second highest bit 267 } 268 269 // Clears lowest 3 bits and highest 23 bits of `f`. 270 func pruneIntermediateScalar(f []byte) { 271 f[0] &= 248 // clear bottom 3 bits 272 f[29] &= 1 // clear 7 high bits 273 f[30] = 0 // clear 8 bits 274 f[31] = 0 // clear 8 bits 275 }