Closed monkeyden closed 3 months ago
Can you check if the signature_ints
and message_bytes
look the same in your JS code?
The message is the same but the signature isn't.
message_ints Python: [123, 34, 109, 101, 115, 115, 97, 103, 101, 34, 58, 32, 34, 83, 105, 103, 110, 45, 105, 110, 32, 116, 111, 32, 82, 117, 103, 99, 104, 101, 99, 107, 46, 120, 121, 122, 34, 44, 32, 34, 116, 105, 109, 101, 115, 116, 97, 109, 112, 34, 58, 32, 49, 55, 50, 51, 48, 55, 55, 50, 48, 53, 57, 51, 57, 44, 32, 34, 112, 117, 98, 108, 105, 99, 75, 101, 121, 34, 58, 32, 34, 52, 98, 75, 109, 89, 104, 104, 97, 98, 90, 109, 85, 68, 87, 86, 54, 120, 57, 122, 52, 76, 55, 57, 107, 97, 66, 77, 85, 66, 117, 102, 69, 55, 78, 99, 76, 50, 49, 110, 75, 72, 103, 78, 51, 34, 125]
JavaScript: [123, 34, 109, 101, 115, 115, 97, 103, 101, 34, 58, 34, 83, 105, 103, 110, 45, 105, 110, 32, 116, 111, 32, 82, 117, 103, 99, 104, 101, 99, 107, 46, 120, 121, 122, 34, 44, 34, 116, 105, 109, 101, 115, 116, 97, 109, 112, 34, 58, 49, 55, 50, 51, 48, 55, 55, 50, 48, 53, 57, 51, 57, 44, 34, 112, 117, 98, 108, 105, 99, 75, 101, 121, 34, 58, 34, 52, 98, 75, 109, 89, 104, 104, 97, 98, 90, 109, 85, 68, 87, 86, 54, 120, 57, 122, 52, 76, 55, 57, 107, 97, 66, 77, 85, 66, 117, 102, 69, 55, 78, 99, 76, 50, 49, 110, 75, 72, 103, 78, 51, 34, 125]
signature_ints Python: [95, 228, 167, 34, 209, 99, 172, 247, 172, 117, 3, 116, 31, 1, 148, 248, 26, 140, 137, 132, 123, 77, 175, 37, 122, 55, 254, 39, 113, 187, 42, 167, 48, 233, 81, 111, 30, 72, 188, 127, 78, 81, 185, 241, 128, 238, 96, 57, 211, 90, 146, 65, 203, 78, 223, 31, 144, 253, 127, 181, 108, 25, 133, 15]
JavaScript: [176, 49, 77, 147, 97, 239, 203, 182, 66, 157, 32, 225, 226, 111, 146, 191, 135, 69, 12, 92, 246, 181, 58, 188, 56, 195, 244, 141, 227, 215, 43, 180, 22, 39, 60, 64, 2, 17, 119, 10, 159, 109, 156, 214, 88, 50, 164, 195, 114, 187, 143, 63, 96, 238, 253, 242, 83, 144, 61, 201, 195, 47, 166, 12]
Here is the JS if you're curious:
<!DOCTYPE html>
<html>
<head>
<title>Solana Sign Message</title>
<script src="https://unpkg.com/@solana/web3.js@latest/lib/index.iife.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/tweetnacl/nacl.min.js"></script>
</head>
<body>
<script>
(async () => {
// Generate a new Keypair or use your existing secret key
const secretKey = Uint8Array.from([your secret key array here]);
const keypair = solanaWeb3.Keypair.fromSecretKey(secretKey);
// Create the message object to sign
const messageObj = {
message: "Sign-in to Rugcheck.xyz",
timestamp: 1723077205939, // Replace this with your specific timestamp
publicKey: keypair.publicKey.toString()
};
// Convert message object to bytes (UTF-8 encoding)
const encodedMessage = new TextEncoder().encode(JSON.stringify(messageObj));
console.log("Message bytes in JavaScript:", Array.from(encodedMessage));
// Sign the message using TweetNacl
const signedMessage = nacl.sign.detached(encodedMessage, keypair.secretKey);
console.log("Signed message:", Array.from(signedMessage));
console.log("Public Key:", keypair.publicKey.toString());
console.log("Message to sign:", JSON.stringify(messageObj));
})();
</script>
</body>
</html>
Oh the message ints are different:
In Python we have 58, 32, 34
Whereas in JS we have 58, 34, 83
Python:
This could simply be the way JSON is serialized between the two. Python seems to use spaces more liberally
python_bytes = [123, 34, 109, 101, 115, 115, 97, 103, 101, 34, 58, 32, 34, 83, 105, 103, 110, 45, 105, 110, 32, 116, 111, 32, 82, 117, 103, 99, 104, 101, 99, 107, 46, 120, 121, 122, 34, 44, 32, 34, 116, 105, 109, 101, 115, 116, 97, 109, 112, 34, 58, 32, 49, 55, 50, 51, 48, 55, 55, 50, 48, 53, 57, 51, 57, 44, 32, 34, 112, 117, 98, 108, 105, 99, 75, 101, 121, 34, 58, 32, 34, 52, 98, 75, 109, 89, 104, 104, 97, 98, 90, 109, 85, 68, 87, 86, 54, 120, 57, 122, 52, 76, 55, 57, 107, 97, 66, 77, 85, 66, 117, 102, 69, 55, 78, 99, 76, 50, 49, 110, 75, 72, 103, 78, 51, 34, 125]
javascript_bytes = [123, 34, 109, 101, 115, 115, 97, 103, 101, 34, 58, 34, 83, 105, 103, 110, 45, 105, 110, 32, 116, 111, 32, 82, 117, 103, 99, 104, 101, 99, 107, 46, 120, 121, 122, 34, 44, 34, 116, 105, 109, 101, 115, 116, 97, 109, 112, 34, 58, 49, 55, 50, 51, 48, 55, 55, 50, 48, 53, 57, 51, 57, 44, 34, 112, 117, 98, 108, 105, 99, 75, 101, 121, 34, 58, 34, 52, 98, 75, 109, 89, 104, 104, 97, 98, 90, 109, 85, 68, 87, 86, 54, 120, 57, 122, 52, 76, 55, 57, 107, 97, 66, 77, 85, 66, 117, 102, 69, 55, 78, 99, 76, 50, 49, 110, 75, 72, 103, 78, 51, 34, 125]
differences = [(i, pb, jb, chr(pb), chr(jb)) for i, (pb, jb) in enumerate(zip(python_bytes, javascript_bytes)) if pb != jb]
for index, p_byte, j_byte, p_char, j_char in differences:
print(f"Difference at index {index}: Python byte {p_byte} ('{p_char}') vs JavaScript byte {j_byte} ('{j_char}')")
yeah this is just something to do with JSON and spaces - before Solders has any involvement
For posterity:
I was indeed doing something wrong. So I'll take full credit for being right there. :sob:
The problem was that I wasn't specifying separators:
json.dumps(request_body)
when it should have been:
json.dumps(request_body, separators=(',', ':'))
Turns out that, when you don't specify the correct separators, dumps() serializes them as "," or ":" followed by a space, which explains the byte array deltas you found.
Thanks for the quick response, and for making solders available to us of course.
I'm making a call to the RugCheck API and need to authenticate in order to get higher rate limits. I have what I think is a fairly simple example.
Overall synopsis: String secret key is converted to an int array Keypair constructed via Keypair.from_bytes() Message signed and verified Signature converted to byte array Body constructed with message and signature Request sent
Seems very simple but I get this back from RugCheck: Authentication failed. Status: 400, Response: {"error":"signature mismatch"}
Here is the payload sent:
I have a near carbon copy in JavaScript that works, so I know the endpoint works. Clearly I am doing something wrong.