web3dart icon indicating copy to clipboard operation
web3dart copied to clipboard

Credentials.signToUint8List fails with RangeError

Open JEndler opened this issue 1 year ago • 1 comments

Hi there,

I'm looking to sign a message to create an AuthSig for LitProtocol. I've been testing the signToUint8List (and signPersonalMessageToUint8List) functions for that.

Unfortunately both of them fail with a Range error: RangeError (RangeError (start): Invalid value: Not in inclusive range 0..32: -32)

Seems like some internal problem with the pointycastle/signers/ecdsa_signer.dart.

I've been generating my Wallet from a mnemonic like this:

// Function to handle mnemonic phrase creation
Future<String> createMnemonicPhrase() async {
  final mnemonic = bip39.generateMnemonic();
  return mnemonic;
}

// Function to handle the creation of an Ethereum wallet from a mnemonic phrase
Future<EthPrivateKey> createEthWalletFromMnemonic(String mnemonic) async {
  // Generate a seed from the mnemonic phrase
  final seedHex = bip39.mnemonicToSeedHex(mnemonic);

  // Create a new Ethereum wallet from the seed
  final EthPrivateKey credentials = EthPrivateKey.fromHex(seedHex);
  return credentials;
}

This yields a seemingly correct 64 byte private key, and normal looking address: Eth Wallet Address: 0xe2895995b51f6509c4d1814e13bfc80925dc67ed

Then, to sign, I'm running this:

String message = "Hello World";
final messageBytes = ascii.encode(message);

// Sign the payload using the user's Ethereum wallet (credentials is type EthPrivateKey)
final signature = credentials.signPersonalMessageToUint8List(messageBytes);

This fails with the above mentioned error message. I've also tried hashing the message to a 32 byte Uint8List using keccak256, that has yielded the same result:

// Convert the message to bytes
final messageBytes = ascii.encode(message);

// hash the payload using keccak256
final digest = KeccakDigest(256); 
final payload = digest.process(messageBytes);

final signature = credentials.signPersonalMessageToUint8List(messageBytes);

Any ideas what might be wrong here? I'm a little out of my depth here 🙃

JEndler avatar Oct 25 '23 10:10 JEndler

For some more context, this is a screenshot of the entire call stack for the error: image

JEndler avatar Oct 25 '23 10:10 JEndler

Found the Issue myself. It wasn't actually a problem with constructing the signature, the failure was with creating the Wallet from the mnemonic phrase. Here's the right way to do that.

// Function to handle the creation of an Ethereum wallet from a mnemonic phrase
Future<EthPrivateKey> createEthWalletFromMnemonic(String mnemonic) async {
  // Constants
  String hdPath = "m/44'/60'/0'/0";

  final isValidMnemonic = bip39.validateMnemonic(mnemonic);
  if (!isValidMnemonic) {
    throw 'Invalid mnemonic';
  }

  final seed = bip39.mnemonicToSeed(mnemonic);
  final root = bip32.BIP32.fromSeed(seed);

  const first = 0;
  final firstChild = root.derivePath("$hdPath/$first");
  final privateKey = HEX.encode(firstChild.privateKey as List<int>);

  // Create a new Ethereum wallet from the seed
  final EthPrivateKey credentials = EthPrivateKey.fromHex(privateKey);
  return credentials;
}

JEndler avatar Jul 18 '24 14:07 JEndler