diff --git a/src/__tests__/starknet.test.ts b/src/__tests__/starknet.test.ts index 1e957dd..cee023f 100644 --- a/src/__tests__/starknet.test.ts +++ b/src/__tests__/starknet.test.ts @@ -43,8 +43,7 @@ describe("Typed Starknet Signer", () => { const expectedSignature = Buffer.from([ 4, 122, 51, 60, 218, 66, 57, 104, 199, 126, 49, 15, 195, 203, 209, 15, 62, 214, 104, 245, 237, 79, 12, 252, 141, 242, 95, 4, 176, 235, 231, 189, 7, 126, 187, 220, 69, 127, 240, 85, 198, 31, 219, 33, 230, 0, 142, 230, 0, 200, 246, 208, 144, 191, 118, 88, 85, 216, 105, 65, 129, 174, 37, - 165, 7, 142, 71, 187, 235, 77, 198, 135, 116, 24, 37, 215, 190, 173, 4, 78, 34, 153, 96, 211, 54, 44, 12, 33, 244, 91, 185, 32, 219, 8, 176, - 196, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 78, 95, 83, 69, 80, 79, 76, 73, 65, + 165, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 78, 95, 83, 69, 80, 79, 76, 73, 65, ]); const data = Buffer.from("Hello Irys!"); @@ -55,10 +54,9 @@ describe("Typed Starknet Signer", () => { it("should fail for an invalid signature", async () => { const expectedSignature = Buffer.from([ - 3, 14, 26, 44, 182, 142, 237, 13, 51, 15, 51, 142, 100, 132, 8, 70, 90, 34, 222, 66, 92, 68, 20, 86, 18, 205, 207, 16, 215, 160, 82, 238, 7, - 227, 27, 134, 157, 27, 47, 233, 175, 89, 26, 104, 127, 142, 192, 227, 45, 149, 179, 169, 202, 38, 75, 242, 68, 84, 75, 8, 222, 153, 188, 225, 7, - 142, 71, 187, 235, 77, 198, 135, 116, 24, 37, 215, 190, 173, 4, 78, 34, 153, 96, 211, 54, 44, 12, 33, 244, 91, 185, 32, 219, 8, 176, 196, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 78, 95, 77, 65, 73, 78, + 4, 122, 51, 60, 218, 66, 57, 104, 199, 126, 49, 15, 195, 203, 209, 15, 62, 214, 104, 245, 237, 79, 12, 252, 141, 242, 95, 4, 176, 235, 231, 189, + 7, 126, 187, 220, 69, 127, 240, 85, 198, 31, 219, 33, 230, 0, 142, 230, 0, 200, 246, 208, 144, 191, 118, 88, 85, 216, 105, 65, 129, 174, 37, + 165, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 78, 95, 83, 69, 80, 79, 76, 73, 65, ]); const data = Buffer.from("Hello World!"); @@ -80,10 +78,9 @@ describe("Typed Starknet Signer", () => { it("should evaulate to false for invalid signature", async () => { // generate invalid signature const signature = Uint8Array.from([ - 3, 14, 26, 44, 182, 142, 237, 13, 51, 15, 51, 142, 100, 132, 8, 70, 90, 34, 222, 66, 92, 68, 20, 86, 18, 205, 207, 16, 215, 160, 82, 238, 7, - 227, 27, 134, 157, 27, 47, 233, 175, 89, 26, 104, 127, 142, 192, 227, 45, 149, 179, 169, 202, 38, 75, 242, 68, 84, 75, 8, 222, 153, 188, 225, 7, - 142, 71, 187, 235, 77, 198, 135, 116, 24, 37, 215, 190, 173, 4, 78, 34, 153, 96, 211, 54, 44, 12, 33, 244, 91, 185, 32, 219, 8, 176, 196, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 78, 95, 77, 65, 73, 78, + 4, 122, 51, 60, 218, 66, 57, 104, 199, 126, 49, 15, 195, 203, 209, 15, 62, 214, 104, 245, 237, 79, 12, 252, 141, 242, 95, 4, 176, 235, 231, 189, + 7, 126, 187, 220, 69, 127, 240, 85, 198, 31, 219, 33, 230, 0, 142, 230, 0, 200, 246, 208, 144, 191, 118, 88, 85, 216, 105, 65, 129, 174, 37, + 165, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 78, 95, 83, 69, 80, 79, 76, 73, 65, ]); // try verifying diff --git a/src/constants.ts b/src/constants.ts index 84413a6..157066d 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -52,8 +52,8 @@ export const SIG_CONFIG: Record = { sigName: "typedEthereum", }, [SignatureConfig.STARKNET]: { - sigLength: 128, // 64 bytes signature, + 32 bytes address + 32 bytes chainId - pubLength: 33, + sigLength: 96, // 64 bytes signature, + 32 bytes chainId + pubLength: 65, // 33 bytes public key + 32 bytes address (for sdk) sigName: "starknet", }, }; diff --git a/src/signing/chains/StarknetSigner.ts b/src/signing/chains/StarknetSigner.ts index a859168..bf33c57 100644 --- a/src/signing/chains/StarknetSigner.ts +++ b/src/signing/chains/StarknetSigner.ts @@ -23,9 +23,15 @@ export default class StarknetSigner implements Signer { public async init(): Promise { const pubKey = encode.addHexPrefix(encode.buf2hex(ec.starkCurve.getPublicKey(this.privateKey, true))); - const hexKey = pubKey.startsWith("0x") ? pubKey.slice(2) : pubKey; + const address = this.signer.address; + + // get pubkey and address buffers + const pubKeyBuffer = Buffer.from(pubKey.startsWith("0x") ? pubKey.slice(2) : pubKey, "hex"); + const addressBuffer = Buffer.from(address.startsWith("0x") ? address.slice(2) : address, "hex"); + + // concatenate buffers as pubKey + this.publicKey = Buffer.concat([pubKeyBuffer, addressBuffer]); - this.publicKey = Buffer.from(hexKey, "hex"); this.chainId = await this.provider.getChainId(); } @@ -43,22 +49,19 @@ export default class StarknetSigner implements Signer { const r = BigInt(signature.r).toString(16).padStart(64, "0"); // Convert BigInt to hex string const s = BigInt(signature.s).toString(16).padStart(64, "0"); // Convert BigInt to hex string - const address = this.signer.address.replace(/^0x0?|^0x/, "").padStart(64, "0"); const rArray = Uint8Array.from(Buffer.from(r, "hex")); const sArray = Uint8Array.from(Buffer.from(s, "hex")); - const addressToArray = Uint8Array.from(Buffer.from(address, "hex")); const chainIdToArray = Uint8Array.from(Buffer.from(chainId.replace(/^0x/, "").padStart(64, "0"), "hex")); // Concatenate the arrays - const result = new Uint8Array(rArray.length + sArray.length + addressToArray.length + chainIdToArray.length); + const result = new Uint8Array(rArray.length + sArray.length + chainIdToArray.length); result.set(rArray); result.set(sArray, rArray.length); - result.set(addressToArray, rArray.length + sArray.length); - result.set(chainIdToArray, rArray.length + sArray.length + addressToArray.length); + result.set(chainIdToArray, rArray.length + sArray.length); // check signature is of required length - if (result.length !== 128) throw new Error("Signature length must be 128 bytes!"); + if (result.length !== 96) throw new Error("Signature length must be 96 bytes!"); return result; } @@ -66,25 +69,23 @@ export default class StarknetSigner implements Signer { static async verify(pubkey: Buffer, message: Uint8Array, signature: Uint8Array, _opts?: any): Promise { const rLength = 32; const sLength = 32; - const addressLength = 32; - const chainIdLength = 32; - // retrieve address from signature - const addressArrayRetrieved = signature.slice(rLength + sLength, rLength + sLength + addressLength); - const originalAddress = "0x" + Buffer.from(addressArrayRetrieved).toString("hex"); + // retrieve pubKey and address from pubKey + const originalPubKey = pubkey.slice(0, 33); + const originalAddress = "0x" + Buffer.from(pubkey.slice(33)).toString("hex"); // retrieve chainId from signature - const chainIdArrayRetrieved = signature.slice(rLength + sLength + addressLength, rLength + sLength + addressLength + chainIdLength); + const chainIdArrayRetrieved = signature.slice(rLength + sLength); const originalChainId = "0x" + Buffer.from(chainIdArrayRetrieved).toString("hex"); // calculate full public key - const fullPubKey = encode.addHexPrefix(encode.buf2hex(pubkey)); + const fullPubKey = encode.addHexPrefix(encode.buf2hex(originalPubKey)); // generate message hash and signature const msg = hash.computeHashOnElements(uint8ArrayToBigNumberishArray(message)); const data: TypedData = getTypedData(msg, originalChainId); const msgHash = typedData.getMessageHash(data, originalAddress); - const trimmedSignature = signature.slice(0, -64); + const trimmedSignature = signature.slice(0, -32); // verify return ec.starkCurve.verify(trimmedSignature, msgHash, fullPubKey); diff --git a/src/signing/chains/injectedStarknetSigner.ts b/src/signing/chains/injectedStarknetSigner.ts index 11ca136..3e06d76 100644 --- a/src/signing/chains/injectedStarknetSigner.ts +++ b/src/signing/chains/injectedStarknetSigner.ts @@ -18,7 +18,16 @@ export default class InjectedStarknetSigner implements Signer { this.walletAccount = walletAccount; } - public async init(): Promise { + public async init(pubKey: string): Promise { + const address = this.walletAccount.address; + + // get pubkey and address buffers + const pubKeyBuffer = Buffer.from(pubKey.startsWith("0x") ? pubKey.slice(2) : pubKey, "hex"); + const addressBuffer = Buffer.from(address.startsWith("0x") ? address.slice(2) : address, "hex"); + + // concatenate buffers as pubKey + this.publicKey = Buffer.concat([pubKeyBuffer, addressBuffer]); + this.chainId = await this.provider.getChainId(); } @@ -36,22 +45,19 @@ export default class InjectedStarknetSigner implements Signer { const rsComponents = Array.from(signature).slice(-2); const r = BigInt(rsComponents[0]).toString(16).padStart(64, "0"); const s = BigInt(rsComponents[1]).toString(16).padStart(64, "0"); - const address = this.walletAccount.address.replace(/^0x0?|^0x/, "").padStart(64, "0"); const rArray = Uint8Array.from(Buffer.from(r, "hex")); const sArray = Uint8Array.from(Buffer.from(s, "hex")); - const addressToArray = Uint8Array.from(Buffer.from(address, "hex")); const chainIdToArray = Uint8Array.from(Buffer.from(chainId.replace(/^0x/, "").padStart(64, "0"), "hex")); // Concatenate the arrays - const result = new Uint8Array(rArray.length + sArray.length + addressToArray.length + chainIdToArray.length); + const result = new Uint8Array(rArray.length + sArray.length + chainIdToArray.length); result.set(rArray); result.set(sArray, rArray.length); - result.set(addressToArray, rArray.length + sArray.length); - result.set(chainIdToArray, rArray.length + sArray.length + addressToArray.length); + result.set(chainIdToArray, rArray.length + sArray.length); // check signature is of required length - if (result.length !== 128) throw new Error("Signature length must be 128 bytes!"); + if (result.length !== 96) throw new Error("Signature length must be 96 bytes!"); return result; } @@ -59,25 +65,23 @@ export default class InjectedStarknetSigner implements Signer { static async verify(pubkey: Buffer, message: Uint8Array, signature: Uint8Array, _opts?: any): Promise { const rLength = 32; const sLength = 32; - const addressLength = 32; - const chainIdLength = 32; - // retrieve address from signature - const addressArrayRetrieved = signature.slice(rLength + sLength, rLength + sLength + addressLength); - const originalAddress = "0x" + Buffer.from(addressArrayRetrieved).toString("hex"); + // retrieve pubKey and address from pubKey + const originalPubKey = pubkey.slice(0, 33); + const originalAddress = "0x" + Buffer.from(pubkey.slice(33)).toString("hex"); // retrieve chainId from signature - const chainIdArrayRetrieved = signature.slice(rLength + sLength + addressLength, rLength + sLength + addressLength + chainIdLength); + const chainIdArrayRetrieved = signature.slice(rLength + sLength); const originalChainId = "0x" + Buffer.from(chainIdArrayRetrieved).toString("hex"); // calculate full public key - const fullPubKey = encode.addHexPrefix(encode.buf2hex(pubkey)); + const fullPubKey = encode.addHexPrefix(encode.buf2hex(originalPubKey)); // generate message hash and signature const msg = hash.computeHashOnElements(uint8ArrayToBigNumberishArray(message)); const data: TypedData = getTypedData(msg, originalChainId); const msgHash = typedData.getMessageHash(data, originalAddress); - const trimmedSignature = signature.slice(0, -64); + const trimmedSignature = signature.slice(0, -32); // verify return ec.starkCurve.verify(trimmedSignature, msgHash, fullPubKey);