1.Schnorr签名
1.1 签名流程
密钥生成(Key Generation)
- 私钥 𝑘k 是一个随机选择的整数,范围为 [1,𝑛−1],其中 𝑛 是椭圆曲线的阶。,
- 公钥 𝑃P 是通过将私钥乘以椭圆曲线的基点 𝐺G 得到的,即 𝑃=𝑘⋅𝐺。
签名生成(Signature Generation)
假设消息为 𝑚。
- 生成随机数 𝑟:选择一个随机数 𝑟r 作为临时私钥,范围为 [1,𝑛−1]。
- 计算非交互式挑战:计算 𝑅=𝑟⋅𝐺,其中 𝐺 是椭圆曲线的基点。
- 计算哈希值:计算哈希值 𝑒:
𝑒=H(𝑅∥𝑃∥𝑚)
- 其中 H 是一个哈希函数,如 SHA-256,𝑅∥𝑃∥𝑚 表示 𝑅、公钥 𝑃 和消息 𝑚 的连接。
- 计算签名:计算签名 𝑠:
𝑠=𝑟+𝑒⋅𝑘(mod𝑛)
- 其中 𝑘 是私钥,𝑒 是哈希值,𝑛n是椭圆曲线的阶。
签名由 (𝑅,𝑠)组成。
签名验证(Signature Verification)
𝑒=H(𝑅∥𝑃∥𝑚)
𝑠⋅𝐺=𝑅+𝑒⋅𝑃
看不懂没关系,我也看不懂,有个概念知道是这三个步骤即可
1.2 签名特点
简洁性
- Schnorr签名算法结构简单,签名过程和验证过程都较为直观。
- 这种简洁性有助于实现和分析安全性
安全性
- 不可伪造:基于离散对数问题的困难性,Schnorr签名在当前已知的计算能力下被认为是安全的
- 欧式证明:有严格的欧式安全性证明。
高效性:
- 计算效率:签名生成和验证的计算效率较高。尤其在批量签名验证中,Schnorr 签名具有显著的性能优势。
- 签名长度:Schnorr 签名的长度较短,相比于 ECDSA 签名,Schnorr 签名占用的存储空间更少。因为签名越短—–>所以花费的gas fees就越少,
扩展性和兼容性
Schnorr 签名支持多种扩展功能,如多重签名(MuSig)和聚合签名。这些扩展功能在增强隐私性和可扩展性方面表现出色。
- 多重签名(MuSig):Schnorr 签名允许多个签名者的公钥和签名聚合为单一的公钥和签名,这显著提高了多重签名的效率和隐私性。
- 兼容性:Schnorr 签名与现有的椭圆曲线加密标准兼容,便于在现有系统中实现和部署。
1.3 签名算法Python代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| import hashlib from ecdsa import SECP256k1, SigningKey, VerifyingKey from ecdsa.curves import Curve
class SchnorrSignObj: curve: Curve def __init__(self): self.curve = SECP256k1
def schnorr_sign(self, private_key, message): signing_key = SigningKey.from_string(private_key, curve=self.curve) verifying_key = signing_key.get_verifying_key()
r = SigningKey.generate(curve=self.curve).privkey.secret_multiplier R = VerifyingKey.from_public_point(r * self.curve.generator, curve=self.curve)
e = hashlib.sha256(R.to_string() + verifying_key.to_string() + message).digest() e = int.from_bytes(e, 'big')
s = (r + e * signing_key.privkey.secret_multiplier) % self.curve.order return R.to_string(), s.to_bytes(32, 'big')
def schnorr_verify(self, public_key, message, signature): R = VerifyingKey.from_string(signature[0], curve=self.curve) s = int.from_bytes(signature[1], 'big')
e = hashlib.sha256(signature[0] + public_key.to_string() + message).digest() e = int.from_bytes(e, 'big')
sG = VerifyingKey.from_public_point(s * self.curve.generator, curve=self.curve) ReP = VerifyingKey.from_public_point(R.pubkey.point + e * public_key.pubkey.point, curve=self.curve) return sG.to_string() == ReP.to_string()
|
测试代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| import schnorr as schnorr
from ecdsa import SECP256k1, SigningKey, VerifyingKey
schnorr_test = schnorr.SchnorrSignObj()
private_key = SigningKey.generate(curve=SECP256k1).to_string() message = b"Hello, Schnorr!2222" signature = schnorr_test.schnorr_sign(private_key, message) print("Signature:", signature)
public_key = VerifyingKey.from_string( SigningKey.from_string(private_key, curve=SECP256k1).get_verifying_key().to_string(), curve=SECP256k1) is_valid = schnorr_test.schnorr_verify(public_key, message, signature)
print("Signature valid:", is_valid)
|
2. BIP86 协议
2.1 结构路径 BIP86 是一种专门为生成 Taproot 地址的路径标准,简化并优化了生成单密钥 Taproot 地址的过程。BIP86 的路径结构如下:
1
| m / 86' / coin_type' / account' / change / address_index
|
- Purpose: 固定为 86’,表示遵循 BIP86 标准。
- Coin Type: 定义特定加密货币的类型,如 0’ 表示比特币。
- Account: 账户索引,允许钱包管理多个独立账户。
- Change: 0 表示外部链(收款地址),1 表示内部链(找零地址)。
- Address Index: 用于生成具体地址的索引。
2.2.地址生成方法
BIP86 使用新的路径结构生成 Taproot 地址,通过椭圆曲线算法派生公钥,并将其编码为 Bech32 格式的地址。生成的 Taproot 地址具有更高的隐私性、安全性和扩展性。
2.3.BIP86 的优势
- 简洁性:BIP86 提供了一种简洁而直观的路径结构,用于生成 Taproot 地址。
- 安全性:BIP86 使用椭圆曲线算法生成公钥,具有与比特币的现有地址生成方法相当的安全性。
- 可扩展性:BIP86 支持不同的币种和账户,具有良好的可扩展性。
3. BIP44 与 BIP86 的区别与联系
3.1.用途上的区别
- BIP44: 通用的多币种、多账户管理,适用于生成多种类型的地址(P2PKH, P2SH, P2WPKH)。
- BIP86: 专门为生成单密钥 Taproot 地址设计,简化了路径和使用场景。
3.2. 路径结构区别
- BIP44: m/44’/coin_type’/account’/change/address_index,包含多币种、多账户和多地址类型。
- BIP86: m/86’/coin_type’/account’/change/address_index,专注于单密钥 Taproot 地址生成。
3.3.复杂性区别
- BIP44: 适用于更复杂的多币种和多账户需求,路径层次更丰富。
- BIP86: 专注于单一用途(Taproot 地址),路径层次简化。
3.4.标准化区别
- BIP44: 广泛应用于各种钱包和加密货币管理系统,已经成为生成确定性钱包路径的标准。
- BIP86: 主要用于比特币的 Taproot 地址生成,随着 Taproot 的采用而变得更加流行。
3.5.总结
- BIP44 适用于多种类型地址生成,适合更复杂的钱包管理需求。
- BIP86 专注于生成比特币的 Taproot 地址,路径简化,专门为 Taproot 设计。
还有BIP84协议,协议很多
4.Taproot 为什么需要 BIP86
4.1. 专注于单密钥 Taproot 地址 :BIP86 专门设计用于生成单密钥 Taproot 地址。Taproot 是比特币的一项重要升级,旨在提高隐私性、可扩展性和智能合约功能。
4.2.符合新标准和优化: BIP86 引入了一些新的优化和改进,以支持比特币协议的新特性,如 Taproot 和 Schnorr 签名。Taproot 和 Schnorr 签名提供了更高的安全性和更好的隐私特性。BIP86 的设计是为了最大限度地利用这些新特性。
4.3.专注于比特币和未来扩展
BIP44 是一个通用的多币种和多账户路径标准,设计用于管理各种加密货币的地址。这种通用性虽然提供了很大的灵活性,但在特定的优化和新特性支持上可能不如专门设计的标准有效。BIP86 专门为比特币设计,更好地支持比特币的未来扩展和改进。
4.4.简化路径和提高效率
BIP86 路径简化,专注于单一用途,使其更适合于生成和管理比特币的 Taproot 地址。这种简化可以减少实现和使用中的复杂性,提高效率和安全性。
4.5.避免混淆和错误
BIP86 的专用路径减少了使用过程中可能出现的混淆和错误。由于它专门设计用于比特币的 Taproot 地址,开发者和用户不必在多个标准之间切换,减少了出错的可能性。
4.6.代码比较
BIP44 代码示范
1 2 3 4 5 6 7 8 9 10 11 12 13
| def create_address(mnemonic): seed = bip39.phrase_to_seed(mnemonic) bip32_root_key = BIP32Key.fromEntropy(seed) path = "m/44'/0'/0'/0/0" key = bip32_root_key for level in path.split('/')[1:]: if level.endswith("'"): index = BIP32_HARDEN + int(level[:-1]) else: index = int(level) key = key.ChildKey(index) address = key.Address() return address
|
BIP86 代码示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| import bip39 import bech32 from bip32 import BIP32, HARDENED_INDEX from hashlib import sha256 from ecdsa import SECP256k1, SigningKey
def generate_taproot_address(mnemonic): seed = bip39.phrase_to_seed(mnemonic) bip32 = BIP32.from_seed(seed) path = "m/86'/0'/0'/0/0" child_key = bip32.get_privkey_from_path(path) private_key = SigningKey.from_string(child_key, curve=SECP256k1) public_key = private_key.get_verifying_key().to_string("compressed") tweak = sha256(b'TapTweak' + public_key[1:]).digest() tweaked_pubkey = bytearray(public_key) for i in range(32): tweaked_pubkey[1 + i] ^= tweak[i] witver = 1 witprog = tweaked_pubkey[1:33] address = bech32.encode('bc', witver, witprog) return address
|
5. Taproot 格式地址离线生成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| import bip39 import bech32 from bip32 import BIP32, HARDENED_INDEX from hashlib import sha256 from ecdsa import SECP256k1, SigningKey
def generate_taproot_address(mnemonic): seed = bip39.phrase_to_seed(mnemonic) bip32 = BIP32.from_seed(seed) path = "m/86'/0'/0'/0/0" child_key = bip32.get_privkey_from_path(path) private_key = SigningKey.from_string(child_key, curve=SECP256k1) public_key = private_key.get_verifying_key().to_string("compressed") tweak = sha256(b'TapTweak' + public_key[1:]).digest() tweaked_pubkey = bytearray(public_key) for i in range(32): tweaked_pubkey[1 + i] ^= tweak[i] witver = 1 witprog = tweaked_pubkey[1:33] address = bech32.encode('bc', witver, witprog) return address
|
6. 离线签名
- 构建交易: 创建并填充交易输入和输出。
- 生成交易摘要: 使用交易数据生成 Taproot 交易摘要。
- 签名交易: 使用私钥对交易摘要进行签名。
- 构建完整交易: 将签名附加到交易中并生成最终的交易。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| def buildAndsignTx(input_list, output_list, private_key, taproot_pubkey): tx = Transaction() for input in input_list: tx.add_input(input['previous_txid'], input['index']) for output in output_list: tx.add_output(output["address"], output["value"]) tx.version = 2 tx.locktime = 0 sighash = tx.signature_hash() tweaked_privkey = taproot_tweak_seckey(private_key, taproot_pubkey) signature = schnorr.sign(tweaked_privkey, sighash) witness = TaprootWitness(taproot_pubkey, signature) tx.inputs[0].witness = witness
signed_tx = tx.serialize() return signed_tx
|
离线签名搞出来,基本交易就OK了,中心化钱包和去中心化钱包的本质区别是私钥管理,签名是一样的。