-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
b298f90
commit 85328bc
Showing
4 changed files
with
163 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
plugins { | ||
id "org.jetbrains.kotlin.jvm" version "1.9.22" | ||
id 'application' | ||
} | ||
|
||
dependencies { | ||
implementation project(':secp256k1-api') | ||
implementation project(':secp256k1-bouncy') | ||
implementation project(':secp256k1-foreign') | ||
implementation 'org.bouncycastle:bcprov-jdk18on:1.77' | ||
} | ||
|
||
application { | ||
//mainClass = 'org.bitcoinj.secp256k1.kotlin.examples.Ecdsa' | ||
mainClass = 'org.bitcoinj.secp256k1.kotlin.examples.Schnorr' | ||
} | ||
|
||
run { | ||
systemProperty "java.library.path", findProperty("javaPath") ?: "" | ||
} | ||
|
83 changes: 83 additions & 0 deletions
83
secp256k1-examples-kotlin/src/main/java/org/bitcoinj/secp256k1/kotlin/examples/Ecdsa.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package org.bitcoinj.secp256k1.kotlin.examples | ||
|
||
import org.bitcoinj.secp256k1.foreign.Secp256k1Foreign | ||
import java.security.MessageDigest | ||
import java.security.NoSuchAlgorithmException | ||
import java.util.* | ||
|
||
/** | ||
* Port of secp256k1 sample `ecdsa.c` to Java | ||
*/ | ||
object Ecdsa { | ||
private val formatter: HexFormat = HexFormat.of() | ||
|
||
/* Instead of signing the message directly, we must sign a 32-byte hash. | ||
* Here the message is "Hello, world!" and the hash function is SHA-256. | ||
* See https://bitcoin.stackexchange.com/questions/81115/if-someone-wanted-to-pretend-to-be-satoshi-by-posting-a-fake-signature-to-defrau/81116#81116 | ||
*/ | ||
private val msg_hash = hash("Hello, world!") | ||
|
||
@JvmStatic | ||
fun main(args: Array<String>) { | ||
println("Running secp256k1-jdk Ecdsa example...") | ||
Secp256k1Foreign().use { secp -> | ||
/* === Key Generation === */ | ||
/* Return a non-zero, in-range private key */ | ||
val privKey = secp.ecPrivKeyCreate() | ||
|
||
//P256k1PrivKey privKey = new BouncyPrivKey(BigInteger.ONE); | ||
|
||
/* Public key creation using a valid context with a verified secret key should never fail */ | ||
val pubkey = secp.ecPubKeyCreate(privKey) | ||
|
||
/* Serialize the pubkey in a compressed form(33 bytes). */ | ||
val compressed_pubkey = secp.ecPubKeySerialize(pubkey, 258 /* secp256k1_h.SECP256K1_EC_COMPRESSED() */) | ||
|
||
/* === Signing === */ | ||
|
||
/* Generate an ECDSA signature using the RFC-6979 safe default nonce. | ||
* Signing with a valid context, verified secret key and the default nonce function should never fail. */ | ||
val sig = secp.ecdsaSign(msg_hash, privKey).unwrap() | ||
|
||
/* Serialize the signature in a compact form. Should always succeed according to | ||
the documentation in secp256k1.h. */ | ||
val serialized_signature = secp.ecdsaSignatureSerializeCompact(sig).unwrap() | ||
|
||
/* === Verification === */ | ||
|
||
/* Deserialize the signature. This will return empty if the signature can't be parsed correctly. */ | ||
val sig2 = secp.ecdsaSignatureParseCompact(serialized_signature).unwrap() | ||
assert(sig.bytes().contentEquals(sig2.bytes())) | ||
/* Deserialize the public key. This will return empty if the public key can't be parsed correctly. */ | ||
val pubkey2 = secp.ecPubKeyParse(compressed_pubkey).unwrap() | ||
assert(pubkey.w == pubkey2.w) | ||
/* Verify a signature. This will return true if it's valid and false if it's not. */ | ||
val is_signature_valid = secp.ecdsaVerify(sig2, msg_hash, pubkey2).unwrap() | ||
|
||
System.out.printf("Is the signature valid? %s\n", is_signature_valid) | ||
System.out.printf("Secret Key: %s\n", privKey.s.toString(16)) | ||
System.out.printf("Public Key (as ECPoint): %s\n", pubkey) | ||
System.out.printf("Public Key (Compressed): %s\n", formatter.formatHex(compressed_pubkey.bytes())) | ||
System.out.printf("Signature: %s\n", formatter.formatHex(serialized_signature.bytes())) | ||
|
||
/* It's best practice to try to clear secrets from memory after using them. | ||
* This is done because some bugs can allow an attacker to leak memory, for | ||
* example through "out of bounds" array access (see Heartbleed), Or the OS | ||
* swapping them to disk. Hence, we overwrite the secret key buffer with zeros. | ||
*/ | ||
privKey.destroy() | ||
} | ||
} | ||
|
||
private fun hash(messageString: String): ByteArray { | ||
val digest: MessageDigest | ||
try { | ||
digest = MessageDigest.getInstance("SHA-256") | ||
} catch (e: NoSuchAlgorithmException) { | ||
throw RuntimeException(e) // Can't happen. | ||
} | ||
val message = messageString.toByteArray() | ||
digest.update(message, 0, message.size) | ||
return digest.digest() | ||
} | ||
} |
58 changes: 58 additions & 0 deletions
58
secp256k1-examples-kotlin/src/main/java/org/bitcoinj/secp256k1/kotlin/examples/Schnorr.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
package org.bitcoinj.secp256k1.kotlin.examples | ||
|
||
import org.bitcoinj.secp256k1.api.P256K1XOnlyPubKey | ||
import org.bitcoinj.secp256k1.foreign.Secp256k1Foreign | ||
import java.util.* | ||
|
||
/** | ||
* | ||
*/ | ||
object Schnorr { | ||
private val formatter: HexFormat = HexFormat.of() | ||
|
||
private const val msg = "Hello, world!" | ||
private const val tag = "my_fancy_protocol" | ||
|
||
@JvmStatic | ||
fun main(args: Array<String>) { | ||
println("Running secp256k1-jdk Schnorr example...") | ||
Secp256k1Foreign().use { secp -> | ||
/* === Key Generation === */ | ||
/* Return a non-zero, in-range private key */ | ||
val keyPair = secp.ecKeyPairCreate() | ||
|
||
//P256K1KeyPair keyPair = secp.ecKeyPairCreate(new BouncyPrivKey(BigInteger.ONE)); | ||
|
||
/* Public key creation using a valid context with a verified secret key should never fail */ | ||
val pubkey = secp.ecPubKeyCreate(keyPair) | ||
|
||
val xOnly = pubkey.xOnly | ||
|
||
val serializedXOnly = xOnly.getSerialized() | ||
|
||
/* === Signing === */ | ||
val msg_hash = secp.taggedSha256(tag, msg) | ||
|
||
val signature = secp.schnorrSigSign32(msg_hash, keyPair) | ||
|
||
/* === Verification === */ | ||
val xOnly2 : P256K1XOnlyPubKey = P256K1XOnlyPubKey.parse(serializedXOnly).unwrap() | ||
|
||
/* Compute the tagged hash on the received message using the same tag as the signer. */ | ||
val msg_hash2 = secp.taggedSha256(tag, msg) | ||
|
||
val is_signature_valid = secp.schnorrSigVerify(signature, msg_hash2, xOnly2).unwrap() | ||
|
||
System.out.printf("Is the signature valid? %s\n", is_signature_valid) | ||
System.out.printf("Secret Key: %s\n", keyPair.s.toString(16)) | ||
System.out.printf("Public Key (as ECPoint): %s\n", formatter.formatHex(xOnly2.serialized)) | ||
System.out.printf("Signature: %s\n", formatter.formatHex(signature)) | ||
|
||
/* It's best practice to try to clear secrets from memory after using them. | ||
* This is done because some bugs can allow an attacker to leak memory, for | ||
* example through "out of bounds" array access (see Heartbleed), Or the OS | ||
* swapping them to disk. Hence, we overwrite the secret key buffer with zeros. */ | ||
keyPair.destroy() | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters