Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BTC signature #1076

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions BTC/signature/README.md
Original file line number Diff line number Diff line change
@@ -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签名将在比特币网络中发挥越来越重要的作用。
29 changes: 29 additions & 0 deletions BTC/signature/ecdsa.js
Original file line number Diff line number Diff line change
@@ -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);
49 changes: 49 additions & 0 deletions BTC/signature/ecdsaPSBT.js
Original file line number Diff line number Diff line change
@@ -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}`);
42 changes: 42 additions & 0 deletions BTC/signature/ecdsaTransaction.js
Original file line number Diff line number Diff line change
@@ -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}`);
17 changes: 17 additions & 0 deletions BTC/signature/package.json
Original file line number Diff line number Diff line change
@@ -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"
}
}
31 changes: 31 additions & 0 deletions BTC/signature/schnorr.js
Original file line number Diff line number Diff line change
@@ -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);
Loading