Flutter区块链签名插件web3_signers的使用
Flutter区块链签名插件web3_signers的使用
web3_signers
是一个Flutter插件,提供了一个统一接口用于在Dart中对EIP-1271消息进行签名。该插件支持以下几种签名方式:
- ✅ Passkey 签名
- ✅ EOA 钱包(基于助记词)
- ✅ 私钥签名
快速概述
首先需要导入 web3_signers
包:
import 'package:web3_signers/web3_signers.dart';
使用Passkeys
Passkey签名器符合multi-signer-interface
,允许您使用设备的Passkeys对负载进行签名。它属于secp256r1类别,并可以使用P256Verifier预编译在链上验证。
final sharedSigner = EthereumAddress.fromHex("0xfD90FAd33ee8b58f32c00aceEad1358e4AFC23f9");
final options = PassKeysOptions(
name: "variance", // 替换为您的依赖方名称
namespace: "variance.space", // 替换为您的依赖方ID(域名)
residentKey: "required",
sharedWebauthnSigner: sharedSigner);
final PassKeySigner pkpSigner = PassKeySigner(options: options);
// 注册一个新的passkey
PassKeyPair pkp = await pkpSigner.register("user@variance.space", "test user");
// 用户名为 `user@variance.space` 并且是必需的
// 显示名称为 `test user` 并且建议在注册时提供它
如果已经知道用户的credentialIds
,可以这样传递knownCredentials
:
final PassKeySigner pkpSigner = PassKeySigner(
...
knownCredentials: Set<Bytes>.from(<Uint8List>[Uint8List(32), Uint8List(32)])>
);
这使得认证器能够过滤呈现给用户以进行签名操作的passkeys。
注意: credential Id’s 在 passkeyPair 中以原始格式和base64格式返回。
Passkey签名方法
有三种方法可以使用passkey签名器签署负载:
- 方法1:使用
personalSign
final sig = await pkpSigner.personalSign(Uint8List(32));
- 方法2:使用
signToEc
final sig = await pkpSigner.signToEc(Uint8List(32));
- 方法3:使用
signToPasskeySignature
final PassKeySignature sig = await pkpSigner.signToPasskeySignature(Uint8List(32));
对于上述每种方法,如果您有已知凭据,则可以通过传递索引来提示认证器使用特定凭据进行签名。例如:await pkpSigner.signToPasskeySignature(Uint8List(32), 2); // 使用索引为2的已知凭据进行签名
使用私钥
私钥签名器符合multi-signer-interface
,是最基本的签名器。
final PrivateKeySigner signer = PrivateKeySigner.createRandom("password");
// 手动实例化私钥签名器
final Random random = Random.secure();
final EthPrivateKey privKey = EthPrivateKey.createRandom(random);
final PrivateKeySigner signer = PrivateKeySigner.create(privKey, "password", random);
// 从加密备份加载
final PrivateKeySigner signer = PrivateKeySigner.fromJson("source", "password");
// 使用任何一种 `personalSign` 或 `signToEc` 方法签署交易
final Uint8List payload = Uint8List(32); // bytes32(0)
final signature = await signer.signToEc(payload);
log("r: ${signature.r}, s: ${signature.s}") // r 和 s 均为 bigint 格式
构建EOA钱包
除了EIP-1271消息之外,web3-signers
包还可以用于开发功能齐全的外部拥有账户(EOA)钱包,如Metamask。
// 创建新的EOA钱包
EOAWallet eoaWallet = EOAWallet.createWallet();
// 默认情况下创建一个12个单词短语的签名器,要创建一个24个单词短语的签名器,需要指定它
eoaWallet = EOAWallet.createWallet(WordLength.word_24); // 返回24个单词短语的签名器
// 检索账户种子短语
final mnemonic = eoaWallet.exportMnemonic();
// 从种子短语恢复EOA钱包
eoaWallet = EOAWallet.recoverAccount(mnemonic);
// 生成新的确定性账户
final accountOne = eoaWallet.addAccount(1);
// 导出账户私钥
final accountZer0PrivKey = eoaWallet.exportPrivateKey(0);
final accountOnePrivKey = eoaWallet.exportPrivateKey(1);
// 获取账户地址
String accountZer0Address = eoaWallet.zerothAddress;
// 或者
accountZer0Address = eoaWallet.getAddress();
final accountOneAddress = eoaWallet.getAddress(index: 1);
完整示例Demo
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:web3_signers/web3_signers.dart';
void main() {
runApp(Web3Signer());
}
class Web3Signer extends StatefulWidget {
const Web3Signer({super.key});
[@override](/user/override)
State<Web3Signer> createState() => _Web3SignerState();
}
class _Web3SignerState extends State<Web3Signer> {
final TextEditingController _textField1Controller = TextEditingController();
final TextEditingController _textField2Controller = TextEditingController();
final TextEditingController _textField3Controller = TextEditingController();
final TextEditingController _textField4Controller = TextEditingController();
static final sharedSigner =
EthereumAddress.fromHex("0xfD90FAd33ee8b58f32c00aceEad1358e4AFC23f9");
static final passkeyOpts = PassKeysOptions(
name: "variance",
namespace: "variance.space",
residentKey: "required",
requireResidentKey: false,
sharedWebauthnSigner: sharedSigner);
final PassKeySigner _pkpSigner = PassKeySigner(options: passkeyOpts);
PassKeyPair? _pkp;
void _auth() async {
_pkp = await _pkpSigner.register("user@variance.space", "test user");
_updatePkpPublicKey();
}
void _signin() async {
if (_pkp != null) {
print("credentialIds: ${_pkp!.authData.b64Credential}");
_pkpSigner.credentialIds.add(_pkp!.authData.rawCredential);
}
final sig = await _pkpSigner.personalSign(Uint8List(32));
final calldata = hexlify(sig);
_updatePkpSignature(calldata);
}
void _updatePkpPublicKey() => setState(() {
_textField1Controller.text = _pkp!.authData.publicKey.item1.toHex();
_textField2Controller.text = _pkp!.authData.publicKey.item2.toHex();
});
void _updatePkpSignature(String calldata) => setState(() {
_textField3Controller.text = calldata;
});
void _clearAllFields() => setState(() {
_textField1Controller.clear();
_textField2Controller.clear();
_textField3Controller.clear();
_textField4Controller.clear();
});
void _getDummySig() => setState(() {
final dummy = _pkpSigner.getDummySignature();
log(dummy);
_textField4Controller.text = dummy;
});
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text(
'Web3 Signer',
),
),
body: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
const Text(
'PublicKeyX:',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500),
),
const SizedBox(width: 10.0),
Expanded(
child: TextField(
controller: _textField1Controller,
decoration: const InputDecoration(),
),
),
],
),
const SizedBox(height: 10.0),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
const Text(
'PublicKeyY:',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500),
),
Expanded(
child: TextField(
controller: _textField2Controller,
decoration: const InputDecoration(),
),
),
],
),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
const Text(
'Signature:',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500),
),
Expanded(
child: TextField(
controller: _textField3Controller,
decoration: const InputDecoration(),
onChanged: (value) {
//检测用户输入
},
onSubmitted: (value) {
//当用户表示他们完成编辑文本框时
},
),
),
],
),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
const Text(
'Dummy:',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500),
),
Expanded(
child: TextField(
controller: _textField4Controller,
decoration: const InputDecoration(),
onChanged: (value) {
//检测用户输入
},
onSubmitted: (value) {
//当用户表示他们完成编辑文本框时
},
),
),
],
),
const SizedBox(height: 100.0),
Row(
children: [
Expanded(
child: ElevatedButton(
style: ElevatedButton.styleFrom(
elevation: 1,
padding: const EdgeInsets.all(20),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
),
),
onPressed: _auth,
child: const Text('Register with Passkey'),
),
),
const SizedBox(
width: 50,
),
Expanded(
child: ElevatedButton(
style: ElevatedButton.styleFrom(
elevation: 1,
padding: const EdgeInsets.all(20),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
),
),
onPressed: _signin,
child: const Text('Sign with Passkey'),
),
),
],
),
const SizedBox(
height: 20,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ElevatedButton(
style: ElevatedButton.styleFrom(
elevation: 1,
padding: const EdgeInsets.all(20),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
),
),
onPressed: _clearAllFields,
child: const Text('Clear fields'),
),
ElevatedButton(
style: ElevatedButton.styleFrom(
elevation: 1,
padding: const EdgeInsets.all(20),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
),
),
onPressed: _getDummySig,
child: const Text('Get dummy Signature'),
),
],
),
],
),
),
),
);
}
}
更多关于Flutter区块链签名插件web3_signers的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter区块链签名插件web3_signers的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是一个关于如何在Flutter项目中使用web3_signers
插件进行区块链签名的代码示例。web3_signers
插件允许你使用私钥对交易或消息进行签名,这在与以太坊区块链交互时非常有用。
首先,确保你的Flutter项目已经添加了对web3dart
和web3_signers
的依赖。在pubspec.yaml
文件中添加以下依赖:
dependencies:
flutter:
sdk: flutter
web3dart: ^2.0.0 # 请检查最新版本号
web3_signers: ^1.0.0 # 请检查最新版本号
然后运行flutter pub get
来获取这些依赖。
接下来,我们编写一个Flutter应用,它使用web3_signers
插件来签名一个消息。
import 'package:flutter/material.dart';
import 'package:web3dart/web3dart.dart';
import 'package:web3_signers/web3_signers.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Flutter Blockchain Signing Example'),
),
body: Center(
child: SignMessageScreen(),
),
),
);
}
}
class SignMessageScreen extends StatefulWidget {
@override
_SignMessageScreenState createState() => _SignMessageScreenState();
}
class _SignMessageScreenState extends State<SignMessageScreen> {
final TextEditingController _privateKeyController = TextEditingController();
final TextEditingController _messageController = TextEditingController();
String? _signature;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextField(
controller: _privateKeyController,
decoration: InputDecoration(labelText: 'Private Key'),
),
SizedBox(height: 16),
TextField(
controller: _messageController,
decoration: InputDecoration(labelText: 'Message'),
),
SizedBox(height: 16),
ElevatedButton(
onPressed: () async {
setState(() {
_signature = null;
});
try {
// 从私钥创建以太坊账户
final privateKey = EthereumAddress.fromHex(_privateKeyController.text).privateKey;
final credentials = EthPrivateKey.fromHex(privateKey);
final signer = credentials.toSigner();
// 要签名的消息(需要先进行Keccak-256哈希)
final messageHash = keccak256(utf8.encode(_messageController.text));
// 使用账户私钥签名消息
final signature = await signer.signMessage(messageHash);
// 将签名结果转换为十六进制字符串
setState(() {
_signature = signature.toHex();
});
} catch (e) {
print('Error signing message: $e');
}
},
child: Text('Sign Message'),
),
SizedBox(height: 16),
if (_signature != null)
Text(
'Signature: $_signature',
style: TextStyle(fontSize: 16),
),
],
),
);
}
}
在这个示例中,我们创建了一个简单的Flutter应用,它允许用户输入一个私钥和一个消息。应用将使用私钥对消息进行签名,并显示签名结果。
关键点解释:
- 私钥和消息输入:用户通过
TextField
输入私钥和消息。 - 创建以太坊账户:使用
EthereumAddress.fromHex
从私钥字符串创建一个以太坊地址对象,然后从中提取私钥。 - 创建签名者:使用
EthPrivateKey.fromHex
从私钥创建一个EthPrivateKey
对象,然后调用toSigner
方法创建一个签名者对象。 - 消息哈希:使用
keccak256
函数对消息进行哈希处理。注意,以太坊中的消息签名通常是对消息的Keccak-256哈希进行签名。 - 签名消息:调用签名者的
signMessage
方法对消息哈希进行签名。 - 显示签名结果:将签名结果转换为十六进制字符串并显示。
请确保在实际应用中妥善管理私钥,避免私钥泄露带来的安全风险。