mirror of
https://github.com/sparrowwallet/drongo.git
synced 2025-11-05 11:56:38 +00:00
align input pubkey retrieval to silent payments reference implementation
This commit is contained in:
parent
7c0aa1545d
commit
0b3b1a5c3f
1 changed files with 47 additions and 5 deletions
|
|
@ -10,13 +10,21 @@ import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class SilentPaymentUtils {
|
public class SilentPaymentUtils {
|
||||||
private static final Logger log = LoggerFactory.getLogger(SilentPaymentUtils.class);
|
private static final Logger log = LoggerFactory.getLogger(SilentPaymentUtils.class);
|
||||||
|
|
||||||
private static final List<ScriptType> SCRIPT_TYPES = List.of(ScriptType.P2TR, ScriptType.P2WPKH, ScriptType.P2SH_P2WPKH, ScriptType.P2PKH);
|
private static final List<ScriptType> SCRIPT_TYPES = List.of(ScriptType.P2TR, ScriptType.P2WPKH, ScriptType.P2SH, ScriptType.P2PKH);
|
||||||
|
|
||||||
|
//Alternative generator point on the secp256k1 curve (x-coordinate) generated from the SHA256 hash of "The scalar for this x is unknown"
|
||||||
|
private static final byte[] NUMS_H = {
|
||||||
|
(byte) 0x50, (byte) 0x92, (byte) 0x9b, (byte) 0x74, (byte) 0xc1, (byte) 0xa0, (byte) 0x49, (byte) 0x54, (byte) 0xb7, (byte) 0x8b, (byte) 0x4b, (byte) 0x60,
|
||||||
|
(byte) 0x35, (byte) 0xe9, (byte) 0x7a, (byte) 0x5e, (byte) 0x07, (byte) 0x8a, (byte) 0x5a, (byte) 0x0f, (byte) 0x28, (byte) 0xec, (byte) 0x96, (byte) 0xd5,
|
||||||
|
(byte) 0x47, (byte) 0xbf, (byte) 0xee, (byte) 0x9a, (byte) 0xce, (byte) 0x80, (byte) 0x3a, (byte) 0xc0
|
||||||
|
};
|
||||||
|
|
||||||
public static boolean isEligible(Transaction tx, Map<HashIndex, Script> spentScriptPubKeys) {
|
public static boolean isEligible(Transaction tx, Map<HashIndex, Script> spentScriptPubKeys) {
|
||||||
if(!containsTaprootOutput(tx)) {
|
if(!containsTaprootOutput(tx)) {
|
||||||
|
|
@ -46,21 +54,55 @@ public class SilentPaymentUtils {
|
||||||
if(scriptType.isScriptType(scriptPubKey)) {
|
if(scriptType.isScriptType(scriptPubKey)) {
|
||||||
switch(scriptType) {
|
switch(scriptType) {
|
||||||
case P2TR:
|
case P2TR:
|
||||||
keys.add(ScriptType.P2TR.getPublicKeyFromScript(scriptPubKey));
|
if(input.getWitness() != null && input.getWitness().getPushCount() >= 1) {
|
||||||
|
List<byte[]> stack = input.getWitness().getPushes();
|
||||||
|
if(stack.size() > 1 && stack.getLast().length > 0 && stack.getLast()[0] == 0x50) { //Last item is annex
|
||||||
|
stack = stack.subList(0, stack.size() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(stack.size() > 1) {
|
||||||
|
// Script path spend
|
||||||
|
byte[] controlBlock = stack.getLast();
|
||||||
|
// Control block is <control byte> <32 byte internal key> and 0 or more <32 byte hash>
|
||||||
|
if(controlBlock.length >= 33) {
|
||||||
|
byte[] internalKey = Arrays.copyOfRange(controlBlock, 1, 33);
|
||||||
|
if(Arrays.equals(internalKey, NUMS_H)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ECKey pubKey = ScriptType.P2TR.getPublicKeyFromScript(scriptPubKey);
|
||||||
|
if(pubKey.isCompressed()) {
|
||||||
|
keys.add(pubKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case P2SH:
|
||||||
|
Script redeemScript = input.getScriptSig().getFirstNestedScript();
|
||||||
|
if(ScriptType.P2WPKH.isScriptType(redeemScript)) {
|
||||||
|
if(input.getWitness() != null && input.getWitness().getPushCount() == 2) {
|
||||||
|
byte[] pubKey = input.getWitness().getPushes().getLast();
|
||||||
|
if(pubKey != null && pubKey.length == 33) {
|
||||||
|
keys.add(ECKey.fromPublicOnly(pubKey));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case P2WPKH:
|
case P2WPKH:
|
||||||
case P2SH_P2WPKH:
|
|
||||||
if(input.getWitness() != null && input.getWitness().getPushCount() == 2) {
|
if(input.getWitness() != null && input.getWitness().getPushCount() == 2) {
|
||||||
byte[] pubKey = input.getWitness().getPushes().get(input.getWitness().getPushCount() - 1);
|
byte[] pubKey = input.getWitness().getPushes().getLast();
|
||||||
if(pubKey != null && pubKey.length == 33) {
|
if(pubKey != null && pubKey.length == 33) {
|
||||||
keys.add(ECKey.fromPublicOnly(pubKey));
|
keys.add(ECKey.fromPublicOnly(pubKey));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case P2PKH:
|
case P2PKH:
|
||||||
|
byte[] spkHash = ScriptType.P2PKH.getHashFromScript(scriptPubKey);
|
||||||
for(ScriptChunk scriptChunk : input.getScriptSig().getChunks()) {
|
for(ScriptChunk scriptChunk : input.getScriptSig().getChunks()) {
|
||||||
if(scriptChunk.isPubKey() && scriptChunk.getData().length == 33) {
|
if(scriptChunk.isPubKey() && scriptChunk.getData().length == 33 && Arrays.equals(Utils.sha256hash160(scriptChunk.getData()), spkHash)) {
|
||||||
keys.add(scriptChunk.getPubKey());
|
keys.add(scriptChunk.getPubKey());
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue