Flutter比特币签名插件bip340的使用

发布于 1周前 作者 htzhanglong 来自 Flutter

Flutter比特币签名插件bip340的使用

插件介绍

bip340 是一个用于实现 BIP-340 Schnorr 签名方案的基本签名和验证功能的 Dart 插件。该插件通过了 BIP-340 测试向量(dart test 可以运行这些测试),但请注意,这并不是安全的加密方式,请勿用于存储比特币。

功能说明

bip340 提供了以下三个主要功能:

  1. 签名 (sign)
    生成符合 BIP-340 方案的 Schnorr 签名。

    String sign(String privateKey, String message, String aux)
    
    • privateKey:必须是 32 字节的小写十六进制编码字符串,即 64 个字符。
    • message:必须是小写十六进制编码的消息哈希(实际消息的哈希)。
    • aux:必须是 32 字节的随机字节,在签名时生成。
    • 返回值:返回一个 64 字节的小写十六进制编码的签名字符串,即 128 个字符。
  2. 验证 (verify)
    验证一个符合 BIP-340 方案的 Schnorr 签名。

    bool verify(String publicKey, String message, String signature)
    
    • publicKey:必须是 32 字节的小写十六进制编码字符串,即 64 个字符(如果你有一个 33 字节的公钥,只需去掉第一个字节)。
    • message:必须是小写十六进制编码的消息哈希(实际消息的哈希)。
    • signature:必须是 64 字节的小写十六进制编码的签名字符串,即 128 个字符。
    • 返回值:如果签名有效,返回 true,否则返回 false
  3. 生成公钥 (getPublicKey)
    从私钥生成公钥。

    String getPublicKey(String privateKey)
    
    • privateKey:必须是 32 字节的十六进制编码字符串,即 64 个字符。
    • 返回值:返回一个 32 字节的十六进制编码的公钥字符串。

完整示例 Demo

下面是一个完整的 Flutter 示例,展示了如何使用 bip340 插件进行签名、验证和生成公钥。

1. 添加依赖

首先,在 pubspec.yaml 文件中添加 bip340 依赖:

dependencies:
  bip340: ^latest_version

2. 创建主文件 main.dart

import 'package:flutter/material.dart';
import 'package:bip340/bip340.dart';
import 'dart:convert'; // 用于 Base64 编码/解码
import 'dart:math'; // 用于生成随机数

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'BIP340 Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: BIP340Demo(),
    );
  }
}

class BIP340Demo extends StatefulWidget {
  [@override](/user/override)
  _BIP340DemoState createState() => _BIP340DemoState();
}

class _BIP340DemoState extends State<BIP340Demo> {
  final TextEditingController _privateKeyController = TextEditingController();
  final TextEditingController _messageController = TextEditingController();
  final TextEditingController _signatureController = TextEditingController();
  final TextEditingController _publicKeyController = TextEditingController();

  String _result = '';

  // 生成 32 字节的随机辅助数据 (aux)
  String generateRandomAux() {
    final random = Random.secure();
    final bytes = List<int>.generate(32, (index) => random.nextInt(256));
    return bytes.map((byte) => byte.toRadixString(16).padLeft(2, '0')).join();
  }

  // 生成 32 字节的随机私钥
  String generateRandomPrivateKey() {
    final random = Random.secure();
    final bytes = List<int>.generate(32, (index) => random.nextInt(256));
    return bytes.map((byte) => byte.toRadixString(16).padLeft(2, '0')).join();
  }

  // 签名
  void signMessage() {
    final privateKey = _privateKeyController.text;
    final message = _messageController.text;
    final aux = generateRandomAux(); // 生成随机辅助数据

    if (privateKey.length != 64 || message.length != 64) {
      setState(() {
        _result = '私钥或消息格式不正确';
      });
      return;
    }

    try {
      final signature = bip340.sign(privateKey, message, aux);
      setState(() {
        _signatureController.text = signature;
        _result = '签名成功: $signature';
      });
    } catch (e) {
      setState(() {
        _result = '签名失败: $e';
      });
    }
  }

  // 验证签名
  void verifySignature() {
    final publicKey = _publicKeyController.text;
    final message = _messageController.text;
    final signature = _signatureController.text;

    if (publicKey.length != 64 || message.length != 64 || signature.length != 128) {
      setState(() {
        _result = '公钥、消息或签名格式不正确';
      });
      return;
    }

    try {
      final isValid = bip340.verify(publicKey, message, signature);
      setState(() {
        _result = isValid ? '签名验证成功' : '签名验证失败';
      });
    } catch (e) {
      setState(() {
        _result = '验证失败: $e';
      });
    }
  }

  // 生成公钥
  void generatePublicKey() {
    final privateKey = _privateKeyController.text;

    if (privateKey.length != 64) {
      setState(() {
        _result = '私钥格式不正确';
      });
      return;
    }

    try {
      final publicKey = bip340.getPublicKey(privateKey);
      setState(() {
        _publicKeyController.text = publicKey;
        _result = '公钥生成成功: $publicKey';
      });
    } catch (e) {
      setState(() {
        _result = '生成公钥失败: $e';
      });
    }
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('BIP340 Demo'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: [
            TextField(
              controller: _privateKeyController,
              decoration: InputDecoration(labelText: '私钥 (64 字节)'),
              maxLength: 64,
            ),
            SizedBox(height: 10),
            TextField(
              controller: _messageController,
              decoration: InputDecoration(labelText: '消息哈希 (64 字节)'),
              maxLength: 64,
            ),
            SizedBox(height: 10),
            TextField(
              controller: _signatureController,
              decoration: InputDecoration(labelText: '签名 (128 字节)'),
              maxLength: 128,
            ),
            SizedBox(height: 10),
            TextField(
              controller: _publicKeyController,
              decoration: InputDecoration(labelText: '公钥 (64 字节)'),
              maxLength: 64,
            ),
            SizedBox(height: 20),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                ElevatedButton(
                  onPressed: signMessage,
                  child: Text('签名'),
                ),
                ElevatedButton(
                  onPressed: verifySignature,
                  child: Text('验证签名'),
                ),
                ElevatedButton(
                  onPressed: generatePublicKey,
                  child: Text('生成公钥'),
                ),
              ],
            ),
            SizedBox(height: 20),
            Text(
              _result,
              style: TextStyle(fontSize: 16, color: _result.startsWith('签名') ? Colors.green : Colors.red),
            ),
          ],
        ),
      ),
    );
  }
}

更多关于Flutter比特币签名插件bip340的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter比特币签名插件bip340的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何在Flutter项目中使用bip340(即Taproot/Schnorr签名的BIP 340)进行比特币签名的代码示例。我们将使用dart_bitcoin库,这是一个流行的Dart比特币工具库,它包含了BIP 340相关的实现。

首先,确保你已经在pubspec.yaml文件中添加了dart_bitcoin依赖:

dependencies:
  flutter:
    sdk: flutter
  dart_bitcoin: ^x.y.z  # 请替换为最新版本号

然后,运行flutter pub get来获取依赖。

接下来,是一个简单的示例代码,展示如何使用BIP 340进行比特币签名:

import 'dart:typed_data';
import 'package:dart_bitcoin/dart_bitcoin.dart';
import 'package:dart_bitcoin/src/bip32/bip32.dart';
import 'package:dart_bitcoin/src/bip340/bip340.dart';
import 'package:pointycastle/export.dart';

void main() {
  // 私钥(示例,实际使用时请替换为你的私钥)
  Uint8List privateKey = Uint8List.fromList(hex.decode('0000000000000000000000000000000000000000000000000000000000000001'));
  
  // 消息(待签名的数据,通常是哈希值)
  Uint8List messageHash = Uint8List.fromList(hex.decode('e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855')); // 这是一个空的SHA-256哈希值

  // 使用私钥生成公钥
  ECPoint publicKey = ECPrivateKey(privateKey).publicKey;
  
  // 创建BIP340签名对象
  BIP340Signer signer = BIP340Signer(privateKey);

  // 生成签名
  BIP340Signature signature = signer.sign(messageHash);

  // 打印公钥和签名
  print('Public Key: ${publicKey.y.toStringAsFixed(0).padLeft(64, '0')}');
  print('Signature: ${signature.r.toStringAsFixed(0).padLeft(64, '0')}${signature.s.toStringAsFixed(0).padLeft(64, '0')}');

  // 验证签名
  bool isValid = BIP340Signer.verify(signature, messageHash, publicKey);
  print('Signature is valid: $isValid');
}

解释:

  1. 私钥:这里我们用一个示例私钥。在实际应用中,你应该使用安全的私钥管理方式。
  2. 消息哈希:待签名的消息通常是一个哈希值。在这个例子中,我们使用了一个空的SHA-256哈希值。
  3. 生成公钥:使用私钥生成相应的公钥。
  4. 创建BIP340签名对象:使用私钥创建一个BIP340签名器。
  5. 生成签名:对消息哈希进行签名。
  6. 打印公钥和签名:输出公钥和生成的签名。
  7. 验证签名:验证生成的签名是否正确。

注意:

  • dart_bitcoin库可能会更新,API可能会有所变化。请查阅最新的文档和源代码以获取最准确的信息。
  • 实际使用时,私钥管理至关重要,请确保私钥的安全存储和访问。
  • 本示例仅用于教育目的,不建议在生产环境中直接使用。

希望这个示例能帮助你理解如何在Flutter项目中使用BIP 340进行比特币签名。

回到顶部