无法验证由 sol-wallet-adapter 签名的消息
Unable to verify message signed by sol-wallet-adapter
created a signed message 我不确定如何使用生成的签名来使用公钥验证消息。
我的用例是,我想使用 Solana 钱包登录 API 服务器,模式如下:
GET message: String (from API server)
sign message with privateKey
POST signature (to API server)
verify signature with stored publicKey
我尝试使用 nodeJS crypto.verify
来解码 API 端的签名消息,但我对缓冲区和椭圆曲线的挖掘有点超出了我的深度:
// Front-end code
const toHexString = (buffer: Buffer) =>
buffer.reduce((str, byte) => str + byte.toString(16).padStart(2, "0"), "");
const data = new TextEncoder().encode('message to verify');
const signed = await wallet.sign(data, "hex");
await setLogin({ // sends API post call to backend
variables: {
publicAddress: walletPublicKey,
signature: toHexString(signed.signature),
},
});
// Current WIP for backend code
const ALGORITHM = "ed25519";
const fromHexString = (hexString) =>
new Uint8Array(hexString.match(/.{1,2}/g).map((byte) => parseInt(byte, 16)));
const signature = fromHexString(args.signature);
const nonceUint8 = new TextEncoder().encode('message to verify');
const verified = crypto.verify(
ALGORITHM,
nonceUint8,
`-----BEGIN PUBLIC KEY-----\n${user.publicAddress}\n-----END PUBLIC KEY-----`,
signature
);
console.log("isVerified: ", verified);
我很确定我正在以错误的方式解决这个问题,而且我一定缺少一个明显的方法。
随着 space 的成熟,我预计验证函数或库似乎会消耗 const signed = await wallet.sign(data, "hex");
的输出
类似于:
import { VerifyMessage } from '@solana/web3.js';
const verified = VerifyMessage(message, publicKey, signature, 'hex');
但是在 3 天的努力之后,我开始达到我的极限并且我的大脑正在衰竭。非常感谢任何帮助或指导
我建议留在 solana-labs trail 并使用 tweetnacl
spl-token-wallet (sollet.io) 用
nacl.sign.detached(message, this.account.secretKey)
在另一端,验证已完成
nacl.sign.detached.verify
在@solana/web3.js
https://github.com/solana-labs/solana/blob/master/web3.js/src/transaction.ts#L560
在你的后端使用 nacl.sign.detached.verify
,你应该是好的。我还建议避免任何数据格式操作,我不确定您要做什么,但如果您确认每个步骤都是正确的。
根据出色的 Project Serum discord 开发人员的意见解决。高级解决方案是使用 sol-wallet-adapter repo 中也使用的库,即 tweetnacl
和 bs58
:
const signatureUint8 = base58.decode(args.signature);
const nonceUint8 = new TextEncoder().encode(user?.nonce);
const pubKeyUint8 = base58.decode(user?.publicAddress);
nacl.sign.detached.verify(nonceUint8, signatureUint8, pubKeyUint8)
// true
我需要将 Uint8Array 转换为字符串并将其转换回 Uint8Array 以进行 HTTP 通信。我发现 Uint8Array 的 toLocaleString
方法在这种情况下很有帮助。它输出 comma-separated 个整数作为字符串。
const signedMessage = await window.solana.signMessage(encodedMessage, "utf8");
const signature = signedMessage.signature.toLocaleString();
然后您可以使用以下代码将其转换回 Uint8Array。
const signatureUint8 = new Uint8Array(signature.split(",").map(Number));
编辑
上面的解决方案在桌面上运行,但当我在 Phantom 钱包 iOS 浏览器中尝试我的代码时,它给出了一个错误。我猜 toLocaleString 方法在该浏览器中不可用。我找到了一个更可靠的解决方案来将 Uint8Array 转换为 comma-separated string
Array.apply([], signedMessage.signature).join(",")
对于iOS,solana.request会报错。使用 solana.signMessage 和 base58 编码签名。
var _signature = '';
try {
signedMessage = await window.solana.request({
method: "signMessage",
params: {
message: encodedMessage
},
});
_signature = signedMessage.signature;
} catch (e) {
try {
signedMessage = await window.solana.signMessage(encodedMessage);
_signature = base58.encode(signedMessage.signature);
} catch (e1) {
alert(e1.message);
}
}
//
try {
signIn('credentials',
{
publicKey: signedMessage.publicKey,
signature: _signature,
callbackUrl: `${window.location.origin}/`
}
)
} catch (e) {
alert(e.message);
}
created a signed message 我不确定如何使用生成的签名来使用公钥验证消息。
我的用例是,我想使用 Solana 钱包登录 API 服务器,模式如下:
GET message: String (from API server)
sign message with privateKey
POST signature (to API server)
verify signature with stored publicKey
我尝试使用 nodeJS crypto.verify
来解码 API 端的签名消息,但我对缓冲区和椭圆曲线的挖掘有点超出了我的深度:
// Front-end code
const toHexString = (buffer: Buffer) =>
buffer.reduce((str, byte) => str + byte.toString(16).padStart(2, "0"), "");
const data = new TextEncoder().encode('message to verify');
const signed = await wallet.sign(data, "hex");
await setLogin({ // sends API post call to backend
variables: {
publicAddress: walletPublicKey,
signature: toHexString(signed.signature),
},
});
// Current WIP for backend code
const ALGORITHM = "ed25519";
const fromHexString = (hexString) =>
new Uint8Array(hexString.match(/.{1,2}/g).map((byte) => parseInt(byte, 16)));
const signature = fromHexString(args.signature);
const nonceUint8 = new TextEncoder().encode('message to verify');
const verified = crypto.verify(
ALGORITHM,
nonceUint8,
`-----BEGIN PUBLIC KEY-----\n${user.publicAddress}\n-----END PUBLIC KEY-----`,
signature
);
console.log("isVerified: ", verified);
我很确定我正在以错误的方式解决这个问题,而且我一定缺少一个明显的方法。
随着 space 的成熟,我预计验证函数或库似乎会消耗 const signed = await wallet.sign(data, "hex");
类似于:
import { VerifyMessage } from '@solana/web3.js';
const verified = VerifyMessage(message, publicKey, signature, 'hex');
但是在 3 天的努力之后,我开始达到我的极限并且我的大脑正在衰竭。非常感谢任何帮助或指导
我建议留在 solana-labs trail 并使用 tweetnacl
spl-token-wallet (sollet.io) 用
nacl.sign.detached(message, this.account.secretKey)
在另一端,验证已完成
nacl.sign.detached.verify
在@solana/web3.js https://github.com/solana-labs/solana/blob/master/web3.js/src/transaction.ts#L560
在你的后端使用 nacl.sign.detached.verify
,你应该是好的。我还建议避免任何数据格式操作,我不确定您要做什么,但如果您确认每个步骤都是正确的。
根据出色的 Project Serum discord 开发人员的意见解决。高级解决方案是使用 sol-wallet-adapter repo 中也使用的库,即 tweetnacl
和 bs58
:
const signatureUint8 = base58.decode(args.signature);
const nonceUint8 = new TextEncoder().encode(user?.nonce);
const pubKeyUint8 = base58.decode(user?.publicAddress);
nacl.sign.detached.verify(nonceUint8, signatureUint8, pubKeyUint8)
// true
我需要将 Uint8Array 转换为字符串并将其转换回 Uint8Array 以进行 HTTP 通信。我发现 Uint8Array 的 toLocaleString
方法在这种情况下很有帮助。它输出 comma-separated 个整数作为字符串。
const signedMessage = await window.solana.signMessage(encodedMessage, "utf8");
const signature = signedMessage.signature.toLocaleString();
然后您可以使用以下代码将其转换回 Uint8Array。
const signatureUint8 = new Uint8Array(signature.split(",").map(Number));
编辑
上面的解决方案在桌面上运行,但当我在 Phantom 钱包 iOS 浏览器中尝试我的代码时,它给出了一个错误。我猜 toLocaleString 方法在该浏览器中不可用。我找到了一个更可靠的解决方案来将 Uint8Array 转换为 comma-separated string
Array.apply([], signedMessage.signature).join(",")
对于iOS,solana.request会报错。使用 solana.signMessage 和 base58 编码签名。
var _signature = '';
try {
signedMessage = await window.solana.request({
method: "signMessage",
params: {
message: encodedMessage
},
});
_signature = signedMessage.signature;
} catch (e) {
try {
signedMessage = await window.solana.signMessage(encodedMessage);
_signature = base58.encode(signedMessage.signature);
} catch (e1) {
alert(e1.message);
}
}
//
try {
signIn('credentials',
{
publicKey: signedMessage.publicKey,
signature: _signature,
callbackUrl: `${window.location.origin}/`
}
)
} catch (e) {
alert(e.message);
}