Skip to content

Commit

Permalink
secp256k1-bitcoinj: Move WitnessMaker to src/main from src/test
Browse files Browse the repository at this point in the history
  • Loading branch information
msgilligan committed Mar 4, 2024
1 parent 5e15025 commit bf0b94c
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 49 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package org.bitcoinj.secp256k1.bitcoinj;

import org.bitcoinj.secp256k1.api.P256K1XOnlyPubKey;
import org.bitcoinj.secp256k1.api.P256k1PubKey;
import org.bitcoinj.secp256k1.api.Secp256k1;
import org.bitcoinj.secp256k1.foreign.PubKeyPojo;

import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
* Experimental class for making P2TR witness programs
*/
public class WitnessMaker {
/**
* 64-byte concatenation of two 32-byte hashes of "TapTweak"
*/
private static final byte[] tweakPrefix = calcTagPrefix64("TapTweak");
private final Secp256k1 secp;

public WitnessMaker(Secp256k1 secp) {
this.secp = secp;
}

public byte[] calcWitnessProgram(P256k1PubKey pubKey) {
P256K1XOnlyPubKey xOnlyKey = pubKey.getXOnly();
BigInteger tweakInt = calcTweak(xOnlyKey);
P256k1PubKey G = new PubKeyPojo(Secp256k1.EC_PARAMS.getGenerator());
P256k1PubKey P2 = secp.ecPubKeyTweakMul(G, tweakInt);
P256k1PubKey Q = secp.ecPubKeyCombine(pubKey, P2);
return Q.getXOnly().getSerialized();
}

public static BigInteger calcTweak(P256K1XOnlyPubKey xOnlyPubKey) {
var digest = newDigest();
digest.update(tweakPrefix);
byte[] hash = digest.digest(xOnlyPubKey.getSerialized());
return new BigInteger(1, hash);
}

public static byte[] calcTagPrefix64(String tag) {
byte[] hash = hash256(tag.getBytes(StandardCharsets.UTF_8));
return ByteBuffer.allocate(64)
.put(hash)
.put(hash)
.array();
}

private static byte[] hash256(byte[] message) {
return newDigest().digest(message);
}

private static MessageDigest newDigest() {
try {
return MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e); // Can't happen.
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* This module contains experimental utility classes for integrating {@code secp256k1-jdk} with <b>bitcoinj</b>.
* If/when a future version of bitcoinj supports secp256k1-jdk and/or Schnorr signatures, this package will likely
* no longer be needed and will be deprecated.
*/
package org.bitcoinj.secp256k1.bitcoinj;
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,12 @@
import org.junit.jupiter.params.provider.MethodSource;

import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.spec.ECPoint;
import java.util.HexFormat;
import java.util.stream.Stream;

import static org.bitcoinj.secp256k1.bitcoinj.WitnessMaker.calcTweak;

/**
*
*/
Expand Down Expand Up @@ -117,49 +115,4 @@ void createAddressTest2() throws Exception {
System.out.println(tapRootAddress);
}

public class WitnessMaker {
private final Secp256k1 secp;

public WitnessMaker(Secp256k1 secp) {
this.secp = secp;
}

public byte[] calcWitnessProgram(P256k1PubKey pubKey) {
P256K1XOnlyPubKey xOnlyKey = pubKey.getXOnly();
BigInteger tweakInt = calcTweak(xOnlyKey);
P256k1PubKey G = new PubKeyPojo(Secp256k1.EC_PARAMS.getGenerator());
P256k1PubKey P2 = secp.ecPubKeyTweakMul(G, tweakInt);
P256k1PubKey Q = secp.ecPubKeyCombine(pubKey, P2);
return Q.getXOnly().getSerialized();
}
}

private BigInteger calcTweak(P256K1XOnlyPubKey xOnlyPubKey) {
var digest = newDigest();
digest.update(tweakPrefix);
byte[] hash = digest.digest(xOnlyPubKey.getSerialized());
return new BigInteger(1, hash);
}

/** 64-byte concatenation of two 32-byte hashes of "TapTweak" */
private static final byte[] tweakPrefix = calcTagPrefix64("TapTweak");

public static byte[] calcTagPrefix64(String tag) {
byte[] hash = hash256(tag.getBytes(StandardCharsets.UTF_8));
return ByteBuffer.allocate(64)
.put(hash)
.put(hash)
.array();
}
private static byte[] hash256(byte[] message) {
return newDigest().digest(message);
}

private static MessageDigest newDigest() {
try {
return MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e); // Can't happen.
}
}
}

0 comments on commit bf0b94c

Please sign in to comment.