runtime-sdk: Add sr25519 support in EVM precompiles#2073
Conversation
✅ Deploy Preview for oasisprotocol-oasis-sdk canceled.
|
087bccb to
f8d82ba
Compare
| } | ||
|
|
||
| /// Verify a signature. | ||
| pub fn verify_raw( |
There was a problem hiding this comment.
This is not in line with other signers, where you have /// Verify signature without using any domain separation scheme., so optionally we could think about renaming this method.
There was a problem hiding this comment.
This matches the polkadot implementation.
f8d82ba to
1a596b9
Compare
|
Constructing STROBE/Merlin transcript requires access to the underlying KeccakF[1600] permutation function, I'm wary that implementing sr25519 signing alone may not be enough if people end up reverting to Solidity to construct the message to be signed, or if the sr25519 signer makes assumption about the transcript which makes it impossible to use for other things. |
|
We can always introduce additional signature modes with different transcripts if needed. This is the easiest way to add into the existing framework, it would be good to know if it is sufficient for the use cases at hand. |
|
Good news: current implementation can verify test case signature. Bad news:
// Key derivation from polkadot test cases
// See: https://github.com/polkadot-js/wasm/blob/10010830094e7d033bd11b16c5e3bc01a7045309/packages/wasm-crypto/src/rs/sr25519.rs#L176
const secretSeed = getBytes("0xfac7959dbfe72f052e5a0c3c8d6530f202b02fd8f9f5ca3580ec8deb7797479e");
const secretKey = sr25519.secretFromSeed(secretSeed);
const publicKey = sr25519.getPublicKey(secretKey);
expect(hexlify(publicKey)).eq("0x46ebddef8cd9bb167dc30878d7113b7e168e6f0646beffd77d69d39bad76b47a");
// Known valid signature
const msg = new TextEncoder().encode("<Bytes>message to sign</Bytes>");
const sig = getBytes("0x48ce2c90e08651adfc8ecef84e916f6d1bb51ebebd16150ee12df247841a5437951ea0f9d632ca165e6ab391532e75e701be6a1caa88c8a6bcca3511f55b4183");
const sigSigner = getBytes("0xf84d048da2ddae2d9d8fd6763f469566e8817a26114f39408de15547f6d47805");
// Verify JS implementation matches polkadot test case signature
const isValid = sr25519.verify(msg, sig, sigSigner);
expect(isValid).eq(true);
const CONTEXT = new TextEncoder().encode('substrate');
// Verify on-chain implementation also works
const result = await se.testVerify(6, sigSigner, CONTEXT, msg, sig);
expect(result).eq(true);
// Test key generation
const generatedKey = await se.testKeygen(6, secretSeed);
// 64 byte secret, appended with 32 byte public key
expect(getBytes(generatedKey.secretKey).length).eq(96);
expect(hexlify(getBytes(generatedKey.secretKey).slice(64))).eq(generatedKey.publicKey);
// JS can verify on-chain signed message
const onchainSigned = await se.testSign(6, generatedKey.secretKey, CONTEXT, msg);
const jsVerify = sr25519.verify(msg, getBytes(onchainSigned), getBytes(generatedKey.publicKey));
expect(jsVerify).eq(true);
// And on-chain can verify on-chain signed message
expect(await se.testVerify(6, generatedKey.publicKey, CONTEXT, msg, onchainSigned)).eq(true);
// JS roundtrip with on-chain generated keypair
const jsSigned = sr25519.sign(getBytes(generatedKey.secretKey).slice(0, 64), msg);
expect(sr25519.verify(msg, jsSigned, getBytes(generatedKey.publicKey))).eq(false); // FAIL
// on-chain verify JS signed message
const onchainVerify = await se.testVerify(6, generatedKey.publicKey, CONTEXT, msg, jsSigned);
expect(onchainVerify).eq(false); // FAIL |
1a596b9 to
2af15ac
Compare
|
The other thing seems to be that there are two ways to encode a keypair:
It looks like we are using |
4b8a0fe to
7af2344
Compare
7af2344 to
7621921
Compare
CedarMist
left a comment
There was a problem hiding this comment.
This matches the Polkadot implementation and passes the tests I made in sapphire-contracts: oasisprotocol/sapphire-paratime#469
…ostko/feature/sr25519-sign f3c7873
…/kostko/feature/sr25519-sign f3c7873
…sisprotocol/kostko/feature/sr25519-sign f3c7873
…oasisprotocol/kostko/feature/sr25519-sign f3c7873
Fixes #1968