From bc55c503ad00da4613718fe07fcdbe1c042e19f1 Mon Sep 17 00:00:00 2001 From: Peter Anyaogu Date: Sat, 2 Nov 2024 19:24:20 +0100 Subject: [PATCH] implement sing typed data and isvalidsignature methods --- CHANGELOG.md | 6 ++ lib/src/interfaces/interfaces.dart | 4 +- .../interfaces/multi_signer_interface.dart | 52 ++++++++++++ .../interfaces/passkey_signer_interface.dart | 34 ++++++++ lib/src/signers/eoa_wallet.dart | 25 ++++++ lib/src/signers/passkey_signer.dart | 65 +++++++++++++- lib/src/signers/private_key_signer.dart | 25 ++++++ lib/src/utils/1271.dart | 31 +++++++ lib/src/utils/crypto.dart | 83 ++++++++++++++++++ lib/src/utils/utils.dart | 2 + lib/src/web3_signers_base.dart | 3 + pubspec.yaml | 3 +- test/constant.dart | 53 ++++++++++++ test/passkey_signer_test.dart | 85 ++++--------------- test/private_key_signer_test.dart | 22 +++++ 15 files changed, 420 insertions(+), 73 deletions(-) create mode 100644 lib/src/utils/1271.dart create mode 100644 test/constant.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index 88ca39c..72930b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 0.1.9 + +- Add support for SignTypedData for signers +- Add ERC-1271 - isValidSignature for signers +- fix incosistent b64 credential encoding in passkeypair and passkeysignature + ## 0.1.8 - fix hardcoded auth attachment diff --git a/lib/src/interfaces/interfaces.dart b/lib/src/interfaces/interfaces.dart index 8584204..fba0f48 100644 --- a/lib/src/interfaces/interfaces.dart +++ b/lib/src/interfaces/interfaces.dart @@ -2,13 +2,15 @@ library interfaces; import 'dart:typed_data'; +import 'package:eth_sig_util/eth_sig_util.dart'; import 'package:passkeys/authenticator.dart' show PasskeyAuthenticator; import 'package:passkeys/types.dart'; import 'package:web3_signers/src/vendor/vendor.dart' show U8aExtension; import 'package:web3dart/crypto.dart'; import 'package:web3dart/web3dart.dart'; -import '../utils/utils.dart' show Uint256, hexlify; +import '../utils/utils.dart' + show ERC1271IsValidSignatureResponse, Uint256, hexlify; import '../web3_signers_base.dart' show PassKeyPair, PassKeySignature; part 'eoa_wallet_interface.dart'; diff --git a/lib/src/interfaces/multi_signer_interface.dart b/lib/src/interfaces/multi_signer_interface.dart index a4d74fb..fc4f022 100644 --- a/lib/src/interfaces/multi_signer_interface.dart +++ b/lib/src/interfaces/multi_signer_interface.dart @@ -1,3 +1,5 @@ +// ignore_for_file: constant_identifier_names + part of 'interfaces.dart'; typedef MSI = MultiSignerInterface; @@ -62,4 +64,54 @@ abstract class MultiSignerInterface { /// final signature = await signToEc(hash, 0); /// ``` Future signToEc(Uint8List hash, {int? index}); + + /// Signs typed data according to EIP-712 standard. + /// + /// Parameters: + /// - [jsonData]: The typed data in JSON format that needs to be signed. + /// - [version]: The version of the typed data standard to use for signing. + /// - [index] optianal value to pass to the function. + /// - can be index to specify which privatekey to use for signing (required for HD wallets). + /// + /// Example: + /// ```dart + /// final jsonData = ''' + /// { + /// "types": { + /// "EIP712Domain": [...], + /// "Mail": [...] + /// }, + /// "primaryType": "Mail", + /// "domain": {...}, + /// "message": {...} + /// } + /// '''; + /// final signature = await signTypedData(jsonData, TypedDataVersion.V4); + /// ``` + Future signTypedData(String jsonData, TypedDataVersion version, + {int? index}); + + /// {@template isValidSignature} + /// Verifies a personal signature against a hash. + /// + /// Parameters: + /// - [hash]: The original hash that was signed. + /// - [signature]: The signature to verify against the hash. + /// - [signer]: The signer address or public key to verify the signature against. + /// {@endtemplate} + /// + /// The signer parameter is generic [T] to support different signer types. + /// This is used to specify the publickey to verify the signature against. + /// and can be the signer address or passkey keypair. + /// The signature parameter is also generic [U] to support different signature formats. + /// Returns [ERC1271IsValidSignatureResponse] magic value. + /// + /// Example: + /// ```dart + /// final hash = Uint8List.fromList([0x01, 0x02, 0x03, 0x04]); + /// final signature = await personalSign(hash); + /// final isValid = await isValidSignature(hash, signature); + /// ``` + Future isValidSignature( + Uint8List hash, U signature, T signer); } diff --git a/lib/src/interfaces/passkey_signer_interface.dart b/lib/src/interfaces/passkey_signer_interface.dart index 46f1b54..e5b43d1 100644 --- a/lib/src/interfaces/passkey_signer_interface.dart +++ b/lib/src/interfaces/passkey_signer_interface.dart @@ -43,6 +43,40 @@ abstract class PasskeySignerInterface extends MultiSignerInterface { Future signToPasskeySignature(Uint8List hash, {List? knownCredentials}); + /// {@macro isValidSignature} + /// - [p256Verifier]: The public key of the P256 verifier. + /// - [rpcUrl]: The URL of the Ethereum JSON-RPC endpoint. + /// + /// Returns a Future representing the validity of the signature. + /// + /// Example: + /// ```dart + /// final hash = Uint8List.fromList([0x01, 0x02, 0x03, 0x04]); + /// final signature = await signToPasskeySignature(hash); + /// final isValid = await isValidPassKeySignature(hash, signature, keypair, p256Verifier, rpcUrl); + /// ``` + Future isValidPassKeySignature( + Uint8List hash, + PassKeySignature signature, + PassKeyPair keypair, + EthereumAddress p256Verifier, + String rpcUrl); + + /// Converts a PassKeySignature to an Safe Smart Account verifiable signature. + /// + /// Parameters: + /// - [signature]: The PassKeySignature to be converted. + /// + /// Returns an FCLSignature representing the converted signature. + /// + /// Example: + /// ```dart + /// final hash = Uint8List.fromList([0x01, 0x02, 0x03, 0x04]); + /// final signature = await signToPasskeySignature(hash); + /// final fclSignature = passkeySignatureToFCLSignature(signature); + /// ``` + FCLSignature passkeySignatureToFCLSignature(PassKeySignature signature); + /// Generates a random base64 string. String randomBase64String(); } diff --git a/lib/src/signers/eoa_wallet.dart b/lib/src/signers/eoa_wallet.dart index 6dd16f8..d96f9ad 100644 --- a/lib/src/signers/eoa_wallet.dart +++ b/lib/src/signers/eoa_wallet.dart @@ -127,6 +127,31 @@ class EOAWallet implements EOAWalletInterface { final hdKey = _getHdKey(index); return _deriveEthPrivKey(hdKey.key.toHex()); } + + @override + Future signTypedData(String jsonData, TypedDataVersion version, + {int? index}) { + final hash = + TypedDataUtil.hashMessage(jsonData: jsonData, version: version); + return personalSign(hash, index: index); + } + + @override + Future isValidSignature( + Uint8List hash, U signature, T address) { + require(signature is Uint8List || signature is MsgSignature, + 'Signature must be of type Uint8List or MsgSignature'); + require( + address is EthereumAddress, 'Address must be of type EthereumAddress'); + address as EthereumAddress; + if (signature is Uint8List) { + return Future.value(isValidPersonalSignature(hash, signature, address)); + } else { + final signer = ecRecover(keccak256(hash), signature as MsgSignature); + return Future.value(ERC1271IsValidSignatureResponse.isValid( + EthereumAddress.fromPublicKey(signer).hex == address.hex)); + } + } } enum WordLength { diff --git a/lib/src/signers/passkey_signer.dart b/lib/src/signers/passkey_signer.dart index 7f34a15..eb74cc8 100644 --- a/lib/src/signers/passkey_signer.dart +++ b/lib/src/signers/passkey_signer.dart @@ -84,8 +84,6 @@ class PassKeySignature { /// final Uint8List encodedSig = pkpSig.toUint8List(); /// ``` Uint8List toUint8List() { - final cdjRgExp = RegExp( - r'^\{"type":"webauthn.get","challenge":"[A-Za-z0-9\-_]{43}",(.*)\}$'); final match = cdjRgExp.firstMatch(clientDataJSON)!; return abi.encode([ 'bytes', @@ -204,6 +202,65 @@ class PassKeySigner implements PasskeySignerInterface { assertion.userHandle); } + @override + Future signTypedData(String jsonData, TypedDataVersion version, + {int? index}) { + final hash = + TypedDataUtil.hashMessage(jsonData: jsonData, version: version); + return personalSign(hash); + } + + @override + Future isValidPassKeySignature( + Uint8List hash, + PassKeySignature signature, + PassKeyPair keypair, + EthereumAddress p256Verifier, + String rpcUrl) async { + final hashBase64 = b64e(hash); + final clientDataJSON = + '{"type":"webauthn.get","challenge":"$hashBase64",${cdjRgExp.firstMatch(signature.clientDataJSON)![1]}}'; + final clientHash = sha256Hash(utf8.encode(clientDataJSON)); + final sigHash = + sha256Hash(signature.authData.concat(Uint8List.fromList(clientHash))); + final calldata = abi.encode([ + "uint256", + "uint256", + "uint256", + "uint256", + "uint256" + ], [ + bytesToInt(sigHash), + signature.signature.item1.value, + signature.signature.item2.value, + keypair.authData.publicKey.item1.value, + keypair.authData.publicKey.item2.value + ]); + final result = await p256Verify(calldata, p256Verifier.hex, rpcUrl); + return ERC1271IsValidSignatureResponse.isValidResult(result); + } + + @override + @Deprecated("use 'isValidPassKeySignature' instead") + Future isValidSignature( + Uint8List hash, U signature, T signer) { + if (signature is PassKeySignature && signer is PassKeyPair) { + final defaultP256Verifier = EthereumAddress.fromHex("0x${'0' * 37}100"); + final defaultRpcUrl = "https://rpc.ankr.com/eth"; + return isValidPassKeySignature( + hash, signature, signer, defaultP256Verifier, defaultRpcUrl); + } else { + throw ArgumentError( + "signature and signer must be of type PassKeySignature and PassKeyPair respectively, we recommend using 'isValidPassKeySignature' from `PasskeySignerInterface` instead"); + } + } + + @override + FCLSignature passkeySignatureToFCLSignature(PassKeySignature signature) { + return _buildSafeSignatureBytes( + _opts.sharedWebauthnSigner, signature.toUint8List()); + } + @override Future register(String username, String displayname, {String? challenge}) async { @@ -251,8 +308,8 @@ class PassKeySigner implements PasskeySignerInterface { final x = Uint256.fromHex(hexlify(keyX.value.value)); final y = Uint256.fromHex(hexlify(keyY.value.value)); - return AuthData(base64Url.encode(credentialId), - Uint8List.fromList(credentialId), Tuple(x, y), aaGUID); + return AuthData(b64e(credentialId), Uint8List.fromList(credentialId), + Tuple(x, y), aaGUID); } AuthData _decodeAttestation(RegisterResponseType attestation) { diff --git a/lib/src/signers/private_key_signer.dart b/lib/src/signers/private_key_signer.dart index a4a4887..dc2335a 100644 --- a/lib/src/signers/private_key_signer.dart +++ b/lib/src/signers/private_key_signer.dart @@ -93,4 +93,29 @@ class PrivateKeySigner implements MultiSignerInterface { "${hexlify(_options.prefix)}fffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c"; String toJson() => _credential.toJson(); + + @override + Future signTypedData(String jsonData, TypedDataVersion version, + {int? index}) { + final hash = + TypedDataUtil.hashMessage(jsonData: jsonData, version: version); + return personalSign(hash); + } + + @override + Future isValidSignature( + Uint8List hash, U signature, T address) { + require(signature is Uint8List || signature is MsgSignature, + 'Signature must be of type Uint8List or MsgSignature'); + require( + address is EthereumAddress, 'Address must be of type EthereumAddress'); + address as EthereumAddress; + if (signature is Uint8List) { + return Future.value(isValidPersonalSignature(hash, signature, address)); + } else { + final signer = ecRecover(keccak256(hash), signature as MsgSignature); + return Future.value(ERC1271IsValidSignatureResponse.isValid( + EthereumAddress.fromPublicKey(signer).hex == address.hex)); + } + } } diff --git a/lib/src/utils/1271.dart b/lib/src/utils/1271.dart new file mode 100644 index 0000000..5d65f7f --- /dev/null +++ b/lib/src/utils/1271.dart @@ -0,0 +1,31 @@ +part of 'utils.dart'; + +enum ERC1271IsValidSignatureResponse { + sucess("0x1626ba7e"), + failure("0xffffffff"); + + final String value; + + const ERC1271IsValidSignatureResponse(this.value); + + factory ERC1271IsValidSignatureResponse.isValid(bool value) { + return value ? sucess : failure; + } + + factory ERC1271IsValidSignatureResponse.isValidResult(Uint256 result) { + return result.value == BigInt.one ? sucess : failure; + } +} + +ERC1271IsValidSignatureResponse isValidPersonalSignature( + Uint8List message, Uint8List signature, EthereumAddress address) { + final prefix = '\u0019Ethereum Signed Message:\n${message.length}'; + final prefixBytes = ascii.encode(prefix); + final payload = prefixBytes.concat(message); + final signer = ecRecover( + keccak256(payload), + MsgSignature(bytesToInt(signature.sublist(0, 32)), + bytesToInt(signature.sublist(32, 64)), signature[64])); + return ERC1271IsValidSignatureResponse.isValid( + EthereumAddress.fromPublicKey(signer).hex == address.hex); +} diff --git a/lib/src/utils/crypto.dart b/lib/src/utils/crypto.dart index 22fc36a..7b0af51 100644 --- a/lib/src/utils/crypto.dart +++ b/lib/src/utils/crypto.dart @@ -2,6 +2,9 @@ part of 'utils.dart'; RegExp _hexadecimal = RegExp(r'^[0-9a-fA-F]+$'); +RegExp cdjRgExp = RegExp( + r'^\{"type":"webauthn.get","challenge":"[A-Za-z0-9\-_]{43}",(.*)\}$'); + /// Generates a Uint8List of random values. /// /// Parameters: @@ -289,3 +292,83 @@ bool isHex(dynamic value, {int bits = -1, bool ignoreLength = false}) { } return false; } + +/// Verifies a P256 signature by making an eth_call to a specified verifier contract. +/// +/// This function sends an RPC request to an Ethereum node to verify P256 signatures using a deployed +/// verifier contract. It handles the JSON-RPC communication and response parsing. +/// +/// Parameters: +/// - [calldata]: The encoded call data containing the signature and message to verify. +/// - [p256Verifier]: The Ethereum address of the deployed P256 verifier contract. +/// - [rpcUrl]: The URL of the Ethereum JSON-RPC endpoint. +/// - [httpClient]: Optional HTTP client for making the RPC request. If not provided, a new one is created. +/// +/// Returns: +/// A [Future] that resolves to: +/// - The verification result from the contract if successful +/// - [Uint256.zero] if there's an error or invalid response +/// +/// Example: +/// ```dart +/// final calldata = Uint8List.fromList([...]); // Your encoded verification data +/// final verifierAddress = "0x123..."; // Your P256 verifier contract address +/// final rpcUrl = "https://eth-mainnet.g.alchemy.com/v2/YOUR-API-KEY"; +/// +/// final result = await p256Verify( +/// calldata, +/// verifierAddress, +/// rpcUrl, +/// ); +/// +/// if (result == Uint256.zero) { +/// print("Verification failed or encountered an error"); +/// } else { +/// print("Verification successful with result: $result"); +/// } +/// ``` +/// +/// Throws: +/// May throw exceptions related to HTTP communication or JSON parsing if the RPC +/// request fails or returns malformed data. +Future p256Verify( + Uint8List calldata, String p256Verifier, String rpcUrl, + [HttpClient? httpClient]) async { + httpClient ??= HttpClient(); + final String requestBody = json.encode({ + 'jsonrpc': '2.0', + 'method': 'eth_call', + 'params': [ + { + 'to': p256Verifier, + 'data': hexlify(calldata), + }, + 'latest' + ], + 'id': 1 + }); + try { + final Uri uri = Uri.parse(rpcUrl); + final HttpClientRequest request = await httpClient.postUrl(uri); + + request.headers.set(HttpHeaders.contentTypeHeader, 'application/json'); + request.add(utf8.encode(requestBody)); + + final HttpClientResponse response = await request.close(); + final String responseBody = await response.transform(utf8.decoder).join(); + + final Map jsonResponse = json.decode(responseBody); + + if (jsonResponse.containsKey('error')) { + return Uint256.zero; + } else if (jsonResponse.containsKey('result')) { + return Uint256.fromHex(jsonResponse['result']); + } else { + return Uint256.zero; + } + } catch (e) { + return Uint256.zero; + } finally { + httpClient.close(); + } +} diff --git a/lib/src/utils/utils.dart b/lib/src/utils/utils.dart index 51eaacf..6b72e14 100644 --- a/lib/src/utils/utils.dart +++ b/lib/src/utils/utils.dart @@ -2,6 +2,7 @@ library; import 'dart:async'; import 'dart:convert'; +import 'dart:io'; import 'dart:math'; import 'dart:typed_data'; import 'dart:developer' as dev; @@ -18,3 +19,4 @@ part 'abi_coder.dart'; part 'crypto.dart'; part 'uint256.dart'; part 'logger.dart'; +part '1271.dart'; diff --git a/lib/src/web3_signers_base.dart b/lib/src/web3_signers_base.dart index e05c717..13bd279 100644 --- a/lib/src/web3_signers_base.dart +++ b/lib/src/web3_signers_base.dart @@ -7,6 +7,7 @@ import 'dart:math'; import 'dart:typed_data'; import 'package:blockchain_utils/blockchain_utils.dart'; +import 'package:eth_sig_util/eth_sig_util.dart'; import 'package:passkeys/authenticator.dart'; import 'package:passkeys/types.dart'; import 'package:web3_signers/src/vendor/vendor.dart' @@ -18,6 +19,8 @@ import 'interfaces/interfaces.dart'; import 'utils/utils.dart'; export 'package:web3dart/web3dart.dart' show EthereumAddress; +import 'package:eth_sig_util/eth_sig_util.dart' + show TypedDataUtil, TypedDataVersion; part 'signers/eoa_wallet.dart'; part 'signers/passkey_signer.dart'; diff --git a/pubspec.yaml b/pubspec.yaml index 3d2a618..2f453e6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: web3_signers description: Web3 signers provides a uniform interface for signing EIP-1271 messages with different EC algorithms. -version: 0.1.8 +version: 0.1.9 homepage: https://variance.space repository: https://github.com/vaariance/web3-signers issue_tracker: https://github.com/vaariance/web3-signers/issues @@ -19,6 +19,7 @@ dependencies: web3dart: ^2.7.3 blockchain_utils: ^3.4.0 asn1lib: ^1.5.5 + eth_sig_util: ^0.0.9 dev_dependencies: mockito: ^5.4.4 diff --git a/test/constant.dart b/test/constant.dart new file mode 100644 index 0000000..1207fab --- /dev/null +++ b/test/constant.dart @@ -0,0 +1,53 @@ +import 'dart:convert'; + +final Map rawTypedData = { + "types": { + "EIP712Domain": [ + {"name": "name", "type": "string"}, + {"name": "version", "type": "string"}, + {"name": "chainId", "type": "uint256"}, + {"name": "verifyingContract", "type": "address"} + ], + "Person": [ + {"name": "name", "type": "string"}, + {"name": "wallets", "type": "address[]"} + ], + "Mail": [ + {"name": "from", "type": "Person"}, + {"name": "to", "type": "Person[]"}, + {"name": "contents", "type": "string"} + ], + "Group": [ + {"name": "name", "type": "string"}, + {"name": "members", "type": "Person[]"} + ] + }, + "domain": { + "name": "Ether Mail", + "version": "1", + "chainId": 1, + "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "primaryType": "Mail", + "message": { + "from": { + "name": "Cow", + "wallets": [ + "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826", + "0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF" + ] + }, + "to": [ + { + "name": "Bob", + "wallets": [ + "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB", + "0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57", + "0xB0B0b0b0b0b0B000000000000000000000000000" + ] + } + ], + "contents": "Hello, Bob!" + } +}; +final jsonData = jsonEncode(rawTypedData); diff --git a/test/passkey_signer_test.dart b/test/passkey_signer_test.dart index dce1a52..a09a176 100644 --- a/test/passkey_signer_test.dart +++ b/test/passkey_signer_test.dart @@ -1,5 +1,4 @@ -import 'dart:io'; - +import 'package:blockchain_utils/blockchain_utils.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:passkeys/types.dart'; import 'package:web3_signers/src/interfaces/interfaces.dart'; @@ -17,7 +16,6 @@ void main() { group('PassKeySigner Tests', () { late PassKeySigner passKeySigner; late MockAuthenticator mockAuthenticator; - late HttpClient httpClient; final options = PassKeysOptions( namespace: 'variance.space', @@ -32,8 +30,7 @@ void main() { "0xedf717baff9a87fd4b031a2a066580a9a29bdba97e2fd55820f7cd5c963f09ae"; final testpkY = "0x276c0acd7ed3c8ad8db88f0c15f5d19b12aaa2af3f26c9003e07afd95b980fe5"; - final cdjRgExp = RegExp( - r'^\{"type":"webauthn.get","challenge":"[A-Za-z0-9\-_]{43}",(.*)\}$'); + final String p256VerifierAddress = '0xc2b78104907F722DABAc4C69f826a522B2754De4'; final String rpcUrl = 'https://rpc.ankr.com/base'; @@ -44,48 +41,8 @@ void main() { // Inject the mock authenticator into the PassKeySigner passKeySigner = PassKeySigner(options: options, auth: mockAuthenticator); - - httpClient = HttpClient(); }); - tearDown(() { - httpClient.close(); - }); - - Future verify(Uint8List calldata) async { - final String requestBody = json.encode({ - 'jsonrpc': '2.0', - 'method': 'eth_call', - 'params': [ - { - 'to': p256VerifierAddress, - 'data': hexlify(calldata), - }, - 'latest' - ], - 'id': 1 - }); - - final Uri uri = Uri.parse(rpcUrl); - final HttpClientRequest request = await httpClient.postUrl(uri); - - request.headers.set(HttpHeaders.contentTypeHeader, 'application/json'); - request.add(utf8.encode(requestBody)); - - final HttpClientResponse response = await request.close(); - final String responseBody = await response.transform(utf8.decoder).join(); - - final Map jsonResponse = json.decode(responseBody); - - if (jsonResponse.containsKey('error')) { - return Uint256.zero; - } else if (jsonResponse.containsKey('result')) { - return Uint256.fromHex(jsonResponse['result']); - } else { - return Uint256.zero; - } - } - test('Initialization of PassKeySigner', () { expect(passKeySigner.opts.namespace, equals('variance.space')); expect(passKeySigner.opts.name, equals('Variance')); @@ -157,28 +114,22 @@ void main() { expect(signature, isA()); - final hashBase64 = b64e(hash); - final clientDataJSON = - '{"type":"webauthn.get","challenge":"$hashBase64",${cdjRgExp.firstMatch(signature.clientDataJSON)![1]}}'; - final clientHash = sha256Hash(utf8.encode(clientDataJSON)); - final sigHash = - sha256Hash(signature.authData.concat(Uint8List.fromList(clientHash))); - final calldata = abi.encode([ - "uint256", - "uint256", - "uint256", - "uint256", - "uint256" - ], [ - bytesToInt(sigHash), - signature.signature.item1.value, - signature.signature.item2.value, - hexToInt(testpkX), - hexToInt(testpkY) - ]); - final valid = await verify(calldata); - - expect(valid.value, equals(BigInt.one)); + final valid = await passKeySigner.isValidPassKeySignature( + hash, + signature, + PassKeyPair( + AuthData( + credentialTestId, + b64d(credentialTestId), + Tuple(Uint256.fromHex(testpkX), Uint256.fromHex(testpkY)), + "aaGUID"), + "username", + null, + null), + EthereumAddress.fromHex(p256VerifierAddress), + rpcUrl); + + expect(valid, equals(ERC1271IsValidSignatureResponse.sucess)); }); test('Register with mocked register method', () async { diff --git a/test/private_key_signer_test.dart b/test/private_key_signer_test.dart index a8082b7..1f7ac25 100644 --- a/test/private_key_signer_test.dart +++ b/test/private_key_signer_test.dart @@ -1,3 +1,4 @@ +import 'package:eth_sig_util/eth_sig_util.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:web3dart/crypto.dart'; import 'package:web3dart/web3dart.dart'; @@ -5,6 +6,8 @@ import 'dart:math'; import 'dart:typed_data'; import 'package:web3_signers/web3_signers.dart'; +import 'constant.dart'; + void main() { group('PrivateKeySigner Tests', () { late PrivateKeySigner signer; @@ -67,5 +70,24 @@ void main() { expect(recoveredSigner, isA()); expect(recoveredSigner.address, equals(signer.address)); }); + + test("isValidSignature", () async { + final hash = Uint8List.fromList(List.generate(32, (index) => index)); + final signature = await signer.personalSign(hash); + + final isValid = + await signer.isValidSignature(hash, signature, signer.address); + expect(isValid, equals(ERC1271IsValidSignatureResponse.sucess)); + }); + + test("signed typed data v4 isValidSignature", () async { + final hash = TypedDataUtil.hashMessage( + jsonData: jsonData, version: TypedDataVersion.V4); + final signature = + await signer.signTypedData(jsonData, TypedDataVersion.V4); + final isValid = + await signer.isValidSignature(hash, signature, signer.address); + expect(isValid, equals(ERC1271IsValidSignatureResponse.sucess)); + }); }); }