|  | 
| 4 | 4 | 	"bytes" | 
| 5 | 5 | 	"encoding/hex" | 
| 6 | 6 | 	"fmt" | 
| 7 |  | - | 
| 8 | 7 | 	"github.com/btcsuite/btcd/btcec" | 
| 9 | 8 | 	"github.com/btcsuite/btcd/chaincfg/chainhash" | 
| 10 | 9 | 	"github.com/btcsuite/btcd/txscript" | 
| @@ -165,51 +164,17 @@ func sweepTimeLockManual(extendedKey *hdkeychain.ExtendedKey, apiURL string, | 
| 165 | 164 | 		commitPoint *btcec.PublicKey | 
| 166 | 165 | 	) | 
| 167 | 166 | 	for i := uint32(0); i < maxKeys; i++ { | 
| 168 |  | -		// The easy part first, let's derive the delay base point. | 
| 169 |  | -		delayPath := []uint32{ | 
| 170 |  | -			lnd.HardenedKey(uint32(keychain.KeyFamilyDelayBase)), 0, | 
| 171 |  | -			i, | 
| 172 |  | -		} | 
| 173 |  | -		delayPrivKey, err := lnd.PrivKeyFromPath(baseKey, delayPath) | 
| 174 |  | -		if err != nil { | 
| 175 |  | -			return err | 
| 176 |  | -		} | 
| 177 |  | - | 
| 178 |  | -		// Get the revocation base point first so we can calculate our | 
| 179 |  | -		// commit point. | 
| 180 |  | -		revPath := []uint32{ | 
| 181 |  | -			lnd.HardenedKey(uint32( | 
| 182 |  | -				keychain.KeyFamilyRevocationRoot, | 
| 183 |  | -			)), 0, i, | 
| 184 |  | -		} | 
| 185 |  | -		revRoot, err := lnd.ShaChainFromPath(baseKey, revPath) | 
| 186 |  | -		if err != nil { | 
| 187 |  | -			return err | 
| 188 |  | -		} | 
| 189 |  | - | 
| 190 |  | -		// We now have everything to brute force the lock script. This | 
| 191 |  | -		// will take a long while as we both have to go through commit | 
| 192 |  | -		// points and CSV values. | 
| 193 |  | -		csvTimeout, script, scriptHash, commitPoint, err = | 
| 194 |  | -			bruteForceDelayPoint( | 
| 195 |  | -				delayPrivKey.PubKey(), remoteRevPoint, revRoot, | 
| 196 |  | -				lockScript, maxCsvTimeout, | 
| 197 |  | -			) | 
|  | 167 | +		csvTimeout, script, scriptHash, commitPoint, delayDesc, err = tryKey( | 
|  | 168 | +			baseKey, remoteRevPoint, maxCsvTimeout, lockScript, i, | 
|  | 169 | +		) | 
| 198 | 170 | 
 | 
| 199 | 171 | 		if err == nil { | 
| 200 |  | -			delayDesc = &keychain.KeyDescriptor{ | 
| 201 |  | -				PubKey: delayPrivKey.PubKey(), | 
| 202 |  | -				KeyLocator: keychain.KeyLocator{ | 
| 203 |  | -					Family: keychain.KeyFamilyDelayBase, | 
| 204 |  | -					Index:  i, | 
| 205 |  | -				}, | 
| 206 |  | -			} | 
|  | 172 | +			log.Infof("Found keys at index %d with CSV timeout %d", | 
|  | 173 | +				i, csvTimeout) | 
| 207 | 174 | 			break | 
| 208 | 175 | 		} | 
| 209 | 176 | 
 | 
| 210 |  | -		if i != 0 && i%20 == 0 { | 
| 211 |  | -			fmt.Printf("Tried %d of %d keys.", i, maxKeys) | 
| 212 |  | -		} | 
|  | 177 | +		log.Infof("Tried %d of %d keys.", i+1, maxKeys) | 
| 213 | 178 | 	} | 
| 214 | 179 | 
 | 
| 215 | 180 | 	// Did we find what we looked for or did we just exhaust all | 
| @@ -318,6 +283,115 @@ func sweepTimeLockManual(extendedKey *hdkeychain.ExtendedKey, apiURL string, | 
| 318 | 283 | 
 | 
| 319 | 284 | } | 
| 320 | 285 | 
 | 
|  | 286 | +func tryKey(baseKey *hdkeychain.ExtendedKey, remoteRevPoint *btcec.PublicKey, | 
|  | 287 | +	maxCsvTimeout uint16, lockScript []byte, idx uint32) (int32, []byte, | 
|  | 288 | +	[]byte, *btcec.PublicKey, *keychain.KeyDescriptor, error) { | 
|  | 289 | + | 
|  | 290 | +	// The easy part first, let's derive the delay base point. | 
|  | 291 | +	delayPath := []uint32{ | 
|  | 292 | +		lnd.HardenedKey(uint32(keychain.KeyFamilyDelayBase)), | 
|  | 293 | +		0, idx, | 
|  | 294 | +	} | 
|  | 295 | +	delayPrivKey, err := lnd.PrivKeyFromPath(baseKey, delayPath) | 
|  | 296 | +	if err != nil { | 
|  | 297 | +		return 0, nil, nil, nil, nil, err | 
|  | 298 | +	} | 
|  | 299 | + | 
|  | 300 | +	// Get the revocation base point first, so we can calculate our | 
|  | 301 | +	// commit point. We start with the old way where the revocation index | 
|  | 302 | +	// was the same as the other indices. | 
|  | 303 | +	revPath := []uint32{ | 
|  | 304 | +		lnd.HardenedKey(uint32( | 
|  | 305 | +			keychain.KeyFamilyRevocationRoot, | 
|  | 306 | +		)), 0, idx, | 
|  | 307 | +	} | 
|  | 308 | +	revRoot, err := lnd.ShaChainFromPath(baseKey, revPath, nil) | 
|  | 309 | +	if err != nil { | 
|  | 310 | +		return 0, nil, nil, nil, nil, err | 
|  | 311 | +	} | 
|  | 312 | + | 
|  | 313 | +	// We now have everything to brute force the lock script. This | 
|  | 314 | +	// will take a long while as we both have to go through commit | 
|  | 315 | +	// points and CSV values. | 
|  | 316 | +	csvTimeout, script, scriptHash, commitPoint, err := bruteForceDelayPoint( | 
|  | 317 | +		delayPrivKey.PubKey(), remoteRevPoint, revRoot, lockScript, | 
|  | 318 | +		maxCsvTimeout, | 
|  | 319 | +	) | 
|  | 320 | +	if err == nil { | 
|  | 321 | +		return csvTimeout, script, scriptHash, commitPoint, | 
|  | 322 | +			&keychain.KeyDescriptor{ | 
|  | 323 | +				PubKey: delayPrivKey.PubKey(), | 
|  | 324 | +				KeyLocator: keychain.KeyLocator{ | 
|  | 325 | +					Family: keychain.KeyFamilyDelayBase, | 
|  | 326 | +					Index:  idx, | 
|  | 327 | +				}, | 
|  | 328 | +			}, nil | 
|  | 329 | +	} | 
|  | 330 | + | 
|  | 331 | +	// Now let's try with the new format where the index is one larger than | 
|  | 332 | +	// the other indices. | 
|  | 333 | +	revPath = []uint32{ | 
|  | 334 | +		lnd.HardenedKey(uint32( | 
|  | 335 | +			keychain.KeyFamilyRevocationRoot, | 
|  | 336 | +		)), 0, idx + 1, | 
|  | 337 | +	} | 
|  | 338 | +	revRoot2, err := lnd.ShaChainFromPath(baseKey, revPath, nil) | 
|  | 339 | +	if err != nil { | 
|  | 340 | +		return 0, nil, nil, nil, nil, err | 
|  | 341 | +	} | 
|  | 342 | + | 
|  | 343 | +	// We now have everything to brute force the lock script. This | 
|  | 344 | +	// will take a long while as we both have to go through commit | 
|  | 345 | +	// points and CSV values. | 
|  | 346 | +	csvTimeout, script, scriptHash, commitPoint, err = bruteForceDelayPoint( | 
|  | 347 | +		delayPrivKey.PubKey(), remoteRevPoint, revRoot2, lockScript, | 
|  | 348 | +		maxCsvTimeout, | 
|  | 349 | +	) | 
|  | 350 | +	if err == nil { | 
|  | 351 | +		return csvTimeout, script, scriptHash, commitPoint, | 
|  | 352 | +			&keychain.KeyDescriptor{ | 
|  | 353 | +				PubKey: delayPrivKey.PubKey(), | 
|  | 354 | +				KeyLocator: keychain.KeyLocator{ | 
|  | 355 | +					Family: keychain.KeyFamilyDelayBase, | 
|  | 356 | +					Index:  idx, | 
|  | 357 | +				}, | 
|  | 358 | +			}, nil | 
|  | 359 | +	} | 
|  | 360 | + | 
|  | 361 | +	// Now we try the same with the new revocation producer format. | 
|  | 362 | +	multiSigPath := []uint32{ | 
|  | 363 | +		lnd.HardenedKey(uint32(keychain.KeyFamilyMultiSig)), | 
|  | 364 | +		0, idx, | 
|  | 365 | +	} | 
|  | 366 | +	multiSigPrivKey, err := lnd.PrivKeyFromPath( | 
|  | 367 | +		baseKey, multiSigPath, | 
|  | 368 | +	) | 
|  | 369 | + | 
|  | 370 | +	revRoot3, err := lnd.ShaChainFromPath( | 
|  | 371 | +		baseKey, revPath, multiSigPrivKey.PubKey(), | 
|  | 372 | +	) | 
|  | 373 | +	if err != nil { | 
|  | 374 | +		return 0, nil, nil, nil, nil, err | 
|  | 375 | +	} | 
|  | 376 | + | 
|  | 377 | +	csvTimeout, script, scriptHash, commitPoint, err = bruteForceDelayPoint( | 
|  | 378 | +		delayPrivKey.PubKey(), remoteRevPoint, revRoot3, lockScript, | 
|  | 379 | +		maxCsvTimeout, | 
|  | 380 | +	) | 
|  | 381 | +	if err == nil { | 
|  | 382 | +		return csvTimeout, script, scriptHash, commitPoint, | 
|  | 383 | +			&keychain.KeyDescriptor{ | 
|  | 384 | +				PubKey: delayPrivKey.PubKey(), | 
|  | 385 | +				KeyLocator: keychain.KeyLocator{ | 
|  | 386 | +					Family: keychain.KeyFamilyDelayBase, | 
|  | 387 | +					Index:  idx, | 
|  | 388 | +				}, | 
|  | 389 | +			}, nil | 
|  | 390 | +	} | 
|  | 391 | + | 
|  | 392 | +	return 0, nil, nil, nil, nil, fmt.Errorf("target script not derived") | 
|  | 393 | +} | 
|  | 394 | + | 
| 321 | 395 | func bruteForceDelayPoint(delayBase, revBase *btcec.PublicKey, | 
| 322 | 396 | 	revRoot *shachain.RevocationProducer, lockScript []byte, | 
| 323 | 397 | 	maxCsvTimeout uint16) (int32, []byte, []byte, *btcec.PublicKey, error) { | 
|  | 
0 commit comments