Skip to content

Commit

Permalink
merge
Browse files Browse the repository at this point in the history
  • Loading branch information
yuanaichi committed Apr 15, 2024
2 parents 2c2052a + 20f1418 commit 2de089d
Show file tree
Hide file tree
Showing 14 changed files with 323 additions and 22 deletions.
1 change: 0 additions & 1 deletion BTC/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

> **CRYPTO IS HARD, DO NOT TRUST ANYONE, VERIFY YOURSELF !!!**
(prodromes)=
## Prodromes

正如开头引用的那句话,加密货币里面涉及到的知识太多了,而且经过十多年的发展,
Expand Down
131 changes: 131 additions & 0 deletions BTC/signature/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
# 比特币中的数字签名

## ECDSA
比特币(BTC)在设计初期使用椭圆曲线数字签名算法(ECDSA)来保证交易的安全性。ECDSA在比特币中的应用提供了强大的安全性,保证交易不可篡改且可验证。它是确保比特币网络信任和安全的关键技术之一。

### 椭圆曲线密码学基础
椭圆曲线定义:在比特币中,通常使用的是secp256k1椭圆曲线。这条曲线在一个有限域上定义,具有一定的形状,能够提供高强度的加密保护。
公钥和私钥:私钥是一个随机选定的数,而公钥是由私钥通过椭圆曲线的数学运算得出的点。

### 生成签名的过程
使用私钥创建签名:签名是使用交易发起者的私钥生成的。这个过程包括对交易的哈希值进行加密处理。
签名组成:ECDSA签名由两部分组成,通常表示为(r, s)。
r:是椭圆曲线点的x坐标。
s:是对交易信息、私钥和一个随机数的数学运算的结果。

### 验证签名的过程
使用公钥验证签名:接收方或网络节点使用发送方的公钥来验证签名。如果签名是有效的,这表明交易是由拥有相应私钥的人发起的,从而保证了交易的真实性和不可否认性。
确保安全性:只有创建签名的私钥持有者才能生成有效的签名,而计算私钥本身几乎是不可能的,因为这需要在有限的时间内解决非常复杂的数学问题。

### 比特币中的应用
交易认证:比特币交易使用ECDSA签名来验证交易的合法性。每笔交易都包括至少一个输入(来源资金)和一个输出(目的地资金)。
防止篡改:ECDSA签名保证了一旦交易被签名,任何对交易内容的修改都会使签名失效,从而防止了交易的篡改。

椭圆曲线密码学提供了比传统的RSA算法更高的安全性,这意味着即使使用更短的密钥,也能提供同等甚至更高的安全性。

### 数学公式
#### 密钥生成 (genKey)
1. 随机产生私钥 $d$,选点 $G$。
2. 计算公钥 $Q = d \* G $

注意事项: $G$点阶数 $n$,但是根据椭圆曲线随机选点 $G$却是计算出来难点。

#### 加密 (encrypt)
1. 选择随机数r的点 $k = r \* G $,随机数r。
2. 计算密文: $C_1 = M + r \* Q $, $C_2 = r \* G $

#### 解密 (decrypt)
1. $C_1 - d \* C_2 = M + r \* Q - r(d \* G) = M + r \* Q - r \* Q = M $

#### 签名 (sign)
1. 对消息m使用哈希算得摘要z,摘要 $z = hash(m)$
2. 生成随机数 $k ∈ [1,n)$,计算点 $k = r \* G $
3. 摘要 $z$, $R = k $,计算 $s = k^{-1}(z + rd) \mod n $,签名为 (r, s)
4. 计算 $s = k^{-1}(z + rd) \mod n $,签名 = (r, s) 即是进行授权协议
5. 以上 $(r, s)$ 即为ECDSA签名

#### 验证 (verify)
使用公钥Q和消息m,对签名 $(r, s)$ 进行验证。

1. 验证 $r, s ∈ [1, n)$
2. 计算 $z = hash(m)$
3. 计算 $u_1 = z \* s^{-1} \mod n$ 和 $u_2 = r \* s^{-1} \mod n $
4. 计算 $(x, y) = u_1 \* G + u_2 \* Q \mod n$
5. 判断 $r == x$,若相等则验证签名正确

#### 恢复 (recover)
已知消息m和签名 $(r, s)$,恢复计算出公钥 $Q$

1. 验证 $r, s ∈ [1, n)$
2. 计算 $R = (x, y)$,其中 $x = r, y + r, y + nr, y + 2nr, ...,$ 代入R到曲线方程计算得到R
3. 计算 $z = hash(m)$
4. 计算 $u_1 = z \* r^{-1} \mod n$ 和 $u_2 = s \* r^{-1} \mod n$
5. 计算公钥 $Q = (x', y') = u_1 \* G + u_2 \* R $


## 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签名将在比特币网络中发挥越来越重要的作用。

### 数学公式
#### 密钥生成 (genKey)
1. 在群的阶 $n$ 内随机选择一个私钥 $d$,通常从 $[1, n)$ 区间选择。
2. 计算公钥 $Q = d \cdot G$,其中 $G$ 是椭圆曲线上的基点。

#### 签名 (sign)
1. 从 $[1, n)$ 区间内随机选取一个数 $k$。
2. 计算 $r = (k \cdot G).x$(即 $k \cdot G$ 点的x坐标)。
3. 计算签名 $s = (k + d \cdot \text{hash}(m)) \mod n$,这里 $\text{hash}(m)$ 是消息 $m$ 的哈希值。
4. 签名结果是一个元组 $(r, s)$。

#### 验证 (verify)
1. 计算 $u1 = \text{hash}(m) \cdot s^{-1} \mod n$。
2. 计算 $u2 = r \cdot s^{-1} \mod n$。
3. 计算点 $R' = u1 \cdot G + u2 \cdot Q$。
4. 验证 $r$ 是否等于 $R'$ 的x坐标,如果相等,则签名有效。

#### 恢复 (recover)
假设我们有一个有效的Schnorr签名 $(r, s)$ 和消息 $m$,以下是计算公钥的步骤:
1. 计算消息的哈希值 $e = \text{hash}(m)$。
2. 计算签名 $s = k + e \cdot d$。
3. 进行 $k \cdot G$ 运算得到 $s \cdot G = k \cdot G + e \cdot d \cdot G$ 即 $s \cdot G = R + e \cdot Q$。
4. 最后,公钥 $Q = (s \cdot G - R) / e$ 计算出来。
5. 其中 $r$ 是 $R$ 的x坐标,可以计算得到 $R$。




## ECDSA VS Schnorr

| 特性 | ECDSA | Schnorr |
|------------|-------------------------------------------|----------------------------------------------|
| 安全性 | 基于椭圆曲线离散对数问题的困难性。随机数重用或泄露会暴露私钥。 | 基于椭圆曲线离散对数问题的困难性。对随机数的选择不敏感,即使随机数可预测,也相对安全。 |
| 效率 | 签名和验证相对复杂,计算量大。 | 签名和验证过程更高效,特别是在批量操作时。 |
| 可组合性 | 无签名可组合性。 | 支持签名聚合,可将多个签名合并为一个。 |
| 签名大小 | 包含两个等长的整数`(r, s)`| 同样包含`(r, s)`对,但因可组合性,最终可能存储更少的签名数据。 |
| 隐私与可证明性 | 无额外隐私保护或可证明性。 | 签名可组合性可用于增强隐私和提供非交互式的多方协议。 |
| 实际应用 | 在众多标准和协议中广泛使用,如比特币和以太坊早期版本。 | 由于技术发展被越来越多的系统采纳,例如比特币的BIP 340提案。 |
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);
20 changes: 11 additions & 9 deletions basic/11-react-express-hardhat/backend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ contract HappyRedPacket is Initializable {
require(_number < 256, "At most 255 recipients");
require(_token_type == 0 || _token_type == 1, "Unrecognizable token type");

// require minium 0.1 for each user
// require minimum 0.1 for each user
require(_total_tokens > 10**(IERC20(_token_addr).decimals() - 1) * _number , "At least 0.1 for each user");

uint256 received_amount = _total_tokens;
Expand Down Expand Up @@ -139,12 +139,12 @@ contract HappyRedPacket is Initializable {
if (total_number - claimed_number == 1)
claimed_tokens = remaining_tokens;
else{
// reserve minium amount => (total_number - claimed_number) * 0.1
// reserve minimum amount => (total_number - claimed_number) * 0.1
uint reserve_amount = (total_number - claimed_number) * minium_value;
uint distribute_tokens = remaining_tokens - reserve_amount;
claimed_tokens = random(seed, nonce) % (distribute_tokens * 2/ (total_number - claimed_number));

// minium claimed_tokens for user is 0.1 ; and round the claimed_tokens to decimal 0.1
// minimum claimed_tokens for user is 0.1 ; and round the claimed_tokens to decimal 0.1
claimed_tokens = claimed_tokens < minium_value ? minium_value : (claimed_tokens - (claimed_tokens % minium_value));
}
} else {
Expand Down
4 changes: 2 additions & 2 deletions defi/Alchemix/contracts/Transmuter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ contract Transmuter is Context {
// NOTE: if last deposit was updated in the same block as the current call
// then the below logic gates will fail

//calculate diffrence in time
//calculate difference in time
uint256 deltaTime = _currentBlock.sub(_lastDepositBlock);

// distribute all if bigger than timeframe
Expand Down Expand Up @@ -297,7 +297,7 @@ contract Transmuter is Context {
// empty bucket
tokensInBucket[toTransmute] = 0;

// calculaate diffrence
// calculaate difference
uint256 diff = pendingz.sub(depositedAlTokens[toTransmute]);

// remove overflow
Expand Down
Loading

0 comments on commit 2de089d

Please sign in to comment.