From f0e79f18796bf32fa9dd2fcab0bfcd8e794d071c Mon Sep 17 00:00:00 2001 From: jasonandjay <342690199@qq.com> Date: Sat, 30 Mar 2024 22:20:02 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=F0=9F=93=84=20docs:=20btc=20signature=20ec?= =?UTF-8?q?dsa=20&=20schnorr?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BTC/signature/index.md | 53 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 BTC/signature/index.md diff --git a/BTC/signature/index.md b/BTC/signature/index.md new file mode 100644 index 000000000..09565d8f2 --- /dev/null +++ b/BTC/signature/index.md @@ -0,0 +1,53 @@ +# 比特币中的数字签名 + +## ECDSA +比特币(BTC)在设计初期使用椭圆曲线数字签名算法(ECDSA)来保证交易的安全性。ECDSA在比特币中的应用提供了强大的安全性,保证交易不可篡改且可验证。它是确保比特币网络信任和安全的关键技术之一。 + +### 椭圆曲线密码学基础 +椭圆曲线定义:在比特币中,通常使用的是secp256k1椭圆曲线。这条曲线在一个有限域上定义,具有一定的形状,能够提供高强度的加密保护。 +公钥和私钥:私钥是一个随机选定的数,而公钥是由私钥通过椭圆曲线的数学运算得出的点。 + +### 生成签名的过程 +使用私钥创建签名:签名是使用交易发起者的私钥生成的。这个过程包括对交易的哈希值进行加密处理。 +签名组成:ECDSA签名由两部分组成,通常表示为(r, s)。 +r:是椭圆曲线点的x坐标。 +s:是对交易信息、私钥和一个随机数的数学运算的结果。 + +### 验证签名的过程 +使用公钥验证签名:接收方或网络节点使用发送方的公钥来验证签名。如果签名是有效的,这表明交易是由拥有相应私钥的人发起的,从而保证了交易的真实性和不可否认性。 +确保安全性:只有创建签名的私钥持有者才能生成有效的签名,而计算私钥本身几乎是不可能的,因为这需要在有限的时间内解决非常复杂的数学问题。 + +### 比特币中的应用 +交易认证:比特币交易使用ECDSA签名来验证交易的合法性。每笔交易都包括至少一个输入(来源资金)和一个输出(目的地资金)。 +防止篡改:ECDSA签名保证了一旦交易被签名,任何对交易内容的修改都会使签名失效,从而防止了交易的篡改。 + +椭圆曲线密码学提供了比传统的RSA算法更高的安全性,这意味着即使使用更短的密钥,也能提供同等甚至更高的安全性。 + + +## Schnorr +比特币的Schnorr签名是一种相对较新的签名算法,它与传统的椭圆曲线数字签名算法(ECDSA)相比,提供了几个关键优势。在2020年的比特币协议升级中,Schnorr签名通过BIP340提案得到了引入。以下是Schnorr签名的详细介绍: + +### Schnorr签名概述 +发明者:Schnorr签名由Claus Schnorr提出。 +算法特性:Schnorr签名基于椭圆曲线密码学,与ECDSA使用相同的椭圆曲线。 +简洁性和效率:Schnorr签名比ECDSA更简洁、高效。它生成的签名更小,处理速度更快。 + +### Schnorr签名的优势 +线性性:Schnorr签名具有线性特性,使得多签名(multi-signature)操作更简单有效。这意味着可以将多个签名组合成一个单一签名,从而减少数据的大小和处理时间。 +隐私和安全性:Schnorr签名提升了隐私和安全性。它使得各种复杂的交易类型(如多签名交易)在区块链上看起来与普通交易无异,从而提高了隐私性。 +防止重放攻击:Schnorr签名包含额外的措施来防止重放攻击,这是ECDSA所缺乏的。 + +### 比特币中的应用 +简化多签名:Schnorr签名简化了比特币网络中的多签名交易处理,减少了数据量和验证所需的时间。 +批量验证:Schnorr签名支持批量验证,允许网络同时验证多个签名,提高了整体效率。 +Taproot升级:结合Schnorr签名的Taproot升级为比特币引入了更高的效率和隐私性。 + +### 签名过程 +私钥和公钥:与ECDSA一样,Schnorr签名使用一对私钥和公钥。 +签名生成:签名是使用私钥和交易的哈希值生成的。Schnorr签名的计算相对简单,它包括了一些线性数学运算。 + +### 全性和效率 +安全性:Schnorr签名被认为至少与ECDSA同等安全,有些专家认为其安全性更高。 +效率和可扩展性:签名的大小和验证的效率对于比特币网络的可扩展性至关重要。Schnorr签名在这方面表现优异。 + +Schnorr签名在比特币中的引入被视为一个重大进步,它提高了交易的隐私性、效率和可扩展性。随着时间的推移,预计Schnorr签名将在比特币网络中发挥越来越重要的作用。 \ No newline at end of file From 6f66c83510ca70a8b4501daaa2cbc85f79dd25d8 Mon Sep 17 00:00:00 2001 From: jasonandjay <342690199@qq.com> Date: Sat, 30 Mar 2024 22:21:32 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E2=9C=A8feature:=20ecdsa=20example,=20incl?= =?UTF-8?q?uding=20combining=20BTC=20transactions=20and=20PSBT?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BTC/signature/ecdsa.js | 29 ++++++++++++++++++ BTC/signature/ecdsaPSBT.js | 49 +++++++++++++++++++++++++++++++ BTC/signature/ecdsaTransaction.js | 42 ++++++++++++++++++++++++++ BTC/signature/package.json | 17 +++++++++++ 4 files changed, 137 insertions(+) create mode 100644 BTC/signature/ecdsa.js create mode 100644 BTC/signature/ecdsaPSBT.js create mode 100644 BTC/signature/ecdsaTransaction.js create mode 100644 BTC/signature/package.json diff --git a/BTC/signature/ecdsa.js b/BTC/signature/ecdsa.js new file mode 100644 index 000000000..41aebf1e4 --- /dev/null +++ b/BTC/signature/ecdsa.js @@ -0,0 +1,29 @@ +import ecpair from 'ecpair'; +import * as tinysecp from "tiny-secp256k1"; +import crypto from 'crypto'; + +/// In this example, we first generate a new private key and corresponding public key. +/// We then create a simulated transaction hash (in a real application, this would be the actual hash of the transaction) and use the private key to sign this hash. +/// Finally, we verify that the signature is valid. + +const { ECPairFactory } = ecpair; +const ECPair = ECPairFactory(tinysecp); + +// Generate a new random private key +const keyPair = ECPair.makeRandom(); +const privateKey = keyPair.privateKey; +const publicKey = keyPair.publicKey; + +console.log('private key:', privateKey.toString('hex')); +console.log('public key:', publicKey.toString('hex')); + +// Create a hypothetical transaction hash, usually this will be the hash of the real transaction you want to sign +const txHash = crypto.randomBytes(32); + +// signature transaction +const signature = keyPair.sign(txHash); +console.log('signature:', signature.toString('hex')); + +// verify transaction +const isValid = keyPair.verify(txHash, signature); +console.log('signature is valid:', isValid); diff --git a/BTC/signature/ecdsaPSBT.js b/BTC/signature/ecdsaPSBT.js new file mode 100644 index 000000000..e8657c7d0 --- /dev/null +++ b/BTC/signature/ecdsaPSBT.js @@ -0,0 +1,49 @@ +import ecpair from 'ecpair'; +import * as tinysecp from "tiny-secp256k1"; +import bitcoin from "bitcoinjs-lib"; + +/// In this example, We get keyPair from WIF. +/// We then construct a PSBT with one input (which you're spending) and one output (where you're sending bitcoins). +/// The PSBT is signed using the private key. +/// Finally, we build the PSBT and print its hexadecimal representation. + +const { ECPairFactory } = ecpair; +const ECPair = ECPairFactory(tinysecp); + +// Get keyPair from WIF +const keyPair = ECPair.fromWIF( + 'L2uPYXe17xSTqbCjZvL2DsyXPCbXspvcu5mHLDYUgzdUbZGSKrSr', +); + +// Create a new PSBT with the first input of the transaction +let psbt = new bitcoin.Psbt() + .addInput({ + hash: '7d067b4a697a09d2c3cff7d4d9506c9955e93bff41bf82d439da7d030382bc3e', + index: 0, + nonWitnessUtxo: Buffer.from( + '0200000001f9f34e95b9d5c8abcd20fc5bd4a825d1517be62f0f775e5f36da944d9' + + '452e550000000006b483045022100c86e9a111afc90f64b4904bd609e9eaed80d48' + + 'ca17c162b1aca0a788ac3526f002207bb79b60d4fc6526329bf18a77135dc566020' + + '9e761da46e1c2f1152ec013215801210211755115eabf846720f5cb18f248666fec' + + '631e5e1e66009ce3710ceea5b1ad13ffffffff01905f0100000000001976a9148bb' + + 'c95d2709c71607c60ee3f097c1217482f518d88ac00000000', + 'hex', + ), + }) + .addOutput({ + address: '1KRMKfeZcmosxALVYESdPNez1AP1mEtywp', + value: 80000, + }); + + +// Sign the first input with the key +psbt.signInput(0, keyPair); + +// Finalize the inputs +psbt.finalizeAllInputs(); + +// Extract the transaction +const rawTx = psbt.extractTransaction().toHex(); + +// Print the transaction +console.log(`Raw Transaction: ${rawTx}`); diff --git a/BTC/signature/ecdsaTransaction.js b/BTC/signature/ecdsaTransaction.js new file mode 100644 index 000000000..e3c93c6fb --- /dev/null +++ b/BTC/signature/ecdsaTransaction.js @@ -0,0 +1,42 @@ +import ecpair from 'ecpair'; +import * as tinysecp from "tiny-secp256k1"; +import bitcoin from "bitcoinjs-lib"; + +/// In this example, We create a new private key and its corresponding public key. +/// We then construct a transaction with one input (which you're spending) and one output (where you're sending bitcoins). +/// The transaction is signed using the private key. +/// Finally, we build the transaction and print its hexadecimal representation. + +const { ECPairFactory } = ecpair; +const ECPair = ECPairFactory(tinysecp); + +// Securely generate and store the private key. Here, we use a randomly generated private key for demonstration. +const keyPair = ECPair.makeRandom(); +const { address } = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey }); +const privateKey = keyPair.privateKey.toString('hex'); + +console.log(`Address: ${address}`); +console.log(`Private Key: ${privateKey}`); + +// Replace the following with a real transaction hash and the corresponding index of the output you want to spend. +const txHash = Buffer.from('c8c5b5a17a07c7cecdbdece070843fb074ae039400a26c27861927dab26631b5', 'hex'); // This should be a real transaction hash +const txId = 1; // Typically 0 or 1 + +// Create a new transaction builder +const transaction = new bitcoin.Transaction(); + +// Add the input (the transaction hash and index) +transaction.addInput(txHash, txId); + +// Add the output (recipient address and amount in satoshis) +transaction.addOutput(Buffer.alloc(0), 10000); // The amount you want to send, in satoshis + +// Sign the transaction with the private key of the input +const hash = transaction.hashForSignature(0, Buffer.from('001494fea8dd42d30e583fdf39537fb7e2ee0533e6b7', 'hex'), 0); +const signature = keyPair.sign(hash); +transaction.setInputScript(0, bitcoin.script.compile([signature, keyPair.publicKey])); + +// Build the transaction and get its hex representation +const tx = transaction.toHex(); + +console.log(`Transaction: ${tx}`); diff --git a/BTC/signature/package.json b/BTC/signature/package.json new file mode 100644 index 000000000..bf4ec8502 --- /dev/null +++ b/BTC/signature/package.json @@ -0,0 +1,17 @@ +{ + "name": "btc-wallet", + "version": "1.0.0", + "description": "", + "main": "index.js", + "type": "module", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "dependencies": { + "bitcoinjs-lib": "^6.1.5", + "ecpair": "^2.1.0", + "tiny-secp256k1": "^2.2.3" + } +} From 23189efc7f4c7f0e6b4f530f93576a2eb6afb376 Mon Sep 17 00:00:00 2001 From: jasonandjay <342690199@qq.com> Date: Sat, 30 Mar 2024 22:22:08 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=E2=9C=A8feature:=20schnorr=20demo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BTC/signature/schnorr.js | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 BTC/signature/schnorr.js diff --git a/BTC/signature/schnorr.js b/BTC/signature/schnorr.js new file mode 100644 index 000000000..fc0e38425 --- /dev/null +++ b/BTC/signature/schnorr.js @@ -0,0 +1,31 @@ +import ecpair from 'ecpair'; +import * as tinysecp from "tiny-secp256k1"; +import crypto from 'crypto'; + +/// In this example, we first generate a new private key and corresponding public key. +/// We create a dummy transaction hash. In a real scenario, this would be the hash of your transaction data. +/// We generate a Schnorr signature using the private key and the transaction hash. +/// Finally, we verify that the signature is valid. + +const { ECPairFactory } = ecpair; +const ECPair = ECPairFactory(tinysecp); + +// Generate a new random private key +const keyPair = ECPair.makeRandom(); +const privateKey = keyPair.privateKey; +const publicKey = keyPair.publicKey; + +console.log('private key:', privateKey.toString('hex')); +console.log('public key:', publicKey.toString('hex')); + +// Create a hypothetical transaction hash, usually this will be the hash of the real transaction you want to sign +const txHash = crypto.randomBytes(32); + + +// signature transaction +const signature = keyPair.signSchnorr(txHash); +console.log('Schnorr Signature:', signature.toString('hex')); + +// verify transaction +const isValid = keyPair.verifySchnorr(txHash, signature); +console.log('signature is valid:', isValid); From 58e26c53c68fd96968f0fecca02ca4b738ca046e Mon Sep 17 00:00:00 2001 From: jasonandjay <342690199@qq.com> Date: Sat, 30 Mar 2024 22:25:00 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=F0=9F=93=84=20docs:=20rename=20README?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BTC/signature/{index.md => README.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename BTC/signature/{index.md => README.md} (100%) diff --git a/BTC/signature/index.md b/BTC/signature/README.md similarity index 100% rename from BTC/signature/index.md rename to BTC/signature/README.md