Closed philoniare closed 2 months ago
Hello @JoshOrndorff , tell us what the redeemer consists of. We have the encoded transaction and the sign function from https://github.com/polkadot-js/wasm/blob/master/packages/wasm-crypto/src/rs/sr25519.rs is it the same signing algoritm that is used in Tuxedo? How can we leverage them to create redeemer?
You are working against the Tuxedo template runtime. It's Verifier type is this one: https://off-narrative-labs.github.io/Tuxedo/tuxedo_template_runtime/enum.OuterVerifier.html You can see it is an enum with three variants. I think you are already focusing on the first variant which is an sr25519 signature. This is good. Continue to focus on this one. For this variant **The redeemer is a plain array of bytes that is exactly the signature.
I believe you guys are working with a Tuxedo version around 36d7baca4ae so I will share links to that commit as well. If you are using a different version, please let me know. A few bits have changed in this logic recently, but the big picture idea is the same.
The exact logic used by the blockchain to check the signatures is this https://github.com/Off-Narrative-Labs/Tuxedo/blob/36d7baca4ae159d77ea545d7cb999bd1e715557d/tuxedo-core/src/verifier.rs#L40-L49 I recommend you add a log line here to print out the bytes received. Then you can check if the Rust code produces the same bytes as the TS.
The signing algo you linked appears to be the correct one. Specifically this appears to be the signing function. https://github.com/polkadot-js/wasm/blob/master/packages/wasm-crypto/src/rs/sr25519.rs#L124
To debug, compare bytes each step of the way. Make sure you derived the same public and private keys between rust and js. Make sure you pass in the same exact message. Make sure you get out the same signature.
This reminds me about the message that needs to be signed. You should sign the entire transaction. But of course the transaction contains the signature itself. To get around this, you must first construct the transaction with everything except the redeemer. It is left blank. Then sign this entire transaction, then insert the signature into the proper place in the transaction. Here is a video of me explaining this at PBA Hong Kong https://youtu.be/cI75Je1Nvk8?si=YTFA20Fd7Ug4i5Tv&t=802 (the video starts at the exact place.)
Please let me know if I can help more, or if we should meet at some point. I really want you guys to have all the support you need.
@JoshOrndorff Yep, thanks. We were able to isolate the issue by following these steps:
Given the above assumptions and the fact that sr25519 signature is deterministic, which means that signing the same bytes with the same private key should result in the same signature, the Talisman signRaw
method is producing a different signature for some reason. So, we're stuck on it at the moment.
the fact that sr25519 signature is deterministic, which means that signing the same bytes with the same private key should result in the same signature
I don't think this is true. https://polkadot.js.org/docs/keyring/start/sign-verify/#using-known-pairs says they are nondeterministic. (And I believe I've observed nondeterminism myself, but I don't remember clearly.)
We had some differences in the encoding, but I've...
Good that you are controlling for that :+1:
Another thought. Remember that in scale, vectors are encoded by first encoding their compact length, then encoding the elements. The redeemer here is a &[u8]
, and TBH, I'm not sure how that is supposed to be encoded in scale (should it have a length prefix or not)? And I don't see it addressed in these reference docs https://docs.substrate.io/reference/scale-codec/
Inspect the working redeemer to see if it is length prefixed. Is it the same length as a plain signature? If so it is not prefixed. If it is longer, are the first few bytes the compact encoded length of the rest of the actual signature? (If the answer to both of those is no then idk wtf.)
Once you've determined whether it should be length prefixed, check whether the one from TS is also length prefixed.
I don't think this is true. https://polkadot.js.org/docs/keyring/start/sign-verify/#using-known-pairs says they are nondeterministic. (And I believe I've observed nondeterminism myself, but I don't remember clearly.)
Got it, still the verifies doesn't pass for some reason.
Thanks for the tip, we'll be looking into it.
Completed implementation with back-end webservice signing
Do you guys need any help figuring out what is going wrong here? I'm open to helping. FYI, you need to sign the entire transaction and insert that signature into the redeemer. Not just sign the redeemer itself.