It seems that the function to create a new keypair (https://solana-labs.github.io/solana-web3.js/classes/Keypair.html#fromSeed) can only take an input string of 32 bytes. This makes sense, but is there a way around this? Would like to create a keypair based on a large text (let's say 1000 characters).
2 Answers
I think the other answer is inaccurate. I won't downvote it though as it's a good attempt to answer the question.
What you're looking for is a key derivation function. PBKDF2 or scrypt are well known key derivation functions. See crypto stack exchange:
A Key derivation function (KDF) is a basic and essential component of cryptographic systems: Its goal is to take a source of initial keying material, usually containing some good amount of randomness, but not distributed uniformly or for which an attacker has some partial knowledge, and derive from it one or more cryptographically strong secret keys.
Addressing the concerns from the other answer to this question:
Cryptographically speaking, text is not random, nor is a hash of text (hashing your 1000 bytes of text shrinks it to 32 bytes and looks "random", but it's as guessable as the text it came from).
This is true, but stretching mild varied input to be sufficiently random output is why KDFs exist.
PBKDF2 is built into both node v18 and browsers as part of webcrypto, so you don't need any third party dependencies. See MDN on PBKDF2.
scrypt is slower, which is better for protecting against hardware accelerated brute force attacks. It's not built into the browser though so you'll need to find an implementation you trust.
You'll also need to salt your inputs, and think of what a good salt would be, to ensure two users with the same input don't have the same output.
In Solana, using PBKDF2 would look like this...
// Import the data as a key to use with webcrypto
const importedKey = await crypto.subtle.importKey(
"raw",
stringBuffer,
"PBKDF2",
false,
["deriveBits"]
);
// Turn the key into entropy (this is where KBDF2 derives the key)
const derivedKey = await crypto.subtle.deriveBits(
{
name: "PBKDF2",
salt,
hash: "SHA-256",
iterations: 100_000,
},
importedKey,
length
);
const mnemonic = bip39.entropyToMnemonic(derivedKey);
You now have a BIP39 mnemonic you can use to generate wallets etc.
The best place for crypto-as-in-cryptography questions is Crypto Stack Exchange.
Keypairs should only ever be created with bytes derived from cryptographically secure random sampling. For example, if you dig deep enough into the dependencies that anchor-py
uses, you'll see it samples from /dev/urandom
.
Cryptographically speaking, text is not random, nor is a hash of text (hashing your 1000 bytes of text shrinks it to 32 bytes and looks "random", but it's as guessable as the text it came from). In general, text is not a secure form of entropy to generate a signing keypair.
If your use case demands content-based addressing, look into program-derived addresses. https://solanacookbook.com/core-concepts/pdas.html#facts
For normal keypair generation, use Keypair.generate()
.
-
1Thank you, but I won't be using it for a wallet. I want to create an account address (public key of the generated keypair) based on text input. Commented Aug 16, 2022 at 20:58
-
1The secure way to base an address on text input is through program-derived addresses, docs cited above. Wallet or not, what you're suggesting doing is a massive security vulnerability, and there are well established code patterns to do literally the same thing, but in a safe, sane way. For any readers -- do not do what this person is thinking of doing! Commented Aug 16, 2022 at 21:21