Created
October 10, 2024 15:30
-
-
Save codeWhizperer/20962bc99c2b87b31a8e3b50ab046366 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import type { RpcProvider, WeierstrassSignatureType, BigNumberish } from "starknet"; | |
| import { Account, ec, encode, hash } from "starknet"; | |
| import type { Signer } from "../index"; | |
| import { SignatureConfig, SIG_CONFIG } from "../../constants"; | |
| export default class StarknetSigner implements Signer { | |
| protected signer: Account; | |
| public publicKey: Buffer; | |
| public address: string; | |
| private privateKey: string; | |
| public provider: RpcProvider; | |
| public chainId: string; | |
| readonly ownerLength: number = SIG_CONFIG[SignatureConfig.STARKNET].pubLength; | |
| readonly signatureLength: number = SIG_CONFIG[SignatureConfig.STARKNET].sigLength; | |
| readonly signatureType: number = SignatureConfig.STARKNET; | |
| constructor(provider: RpcProvider, address: string, pKey: string) { | |
| this.provider = provider; | |
| this.address = address; | |
| this.privateKey = pKey; | |
| this.signer = new Account(provider, address, pKey); | |
| } | |
| public async init(): Promise<void> { | |
| try { | |
| const pub_key = encode.addHexPrefix(encode.buf2hex(ec.starkCurve.getPublicKey(this.privateKey, true))); | |
| const hexKey = pub_key.startsWith("0x") ? pub_key.slice(2) : pub_key; | |
| this.publicKey = Buffer.from(hexKey, "hex"); | |
| this.chainId = await this.provider.getChainId(); | |
| } catch (error) { | |
| console.error("Error setting public key or chain ID:", error); | |
| } | |
| } | |
| async sign(message: Uint8Array, _opts?: any): Promise<Uint8Array> { | |
| if (!this.publicKey) { | |
| await this.init(); | |
| } | |
| if (!this.signer.signMessage) throw new Error("Selected signer does not support message signing"); | |
| // generate message hash and signature | |
| const msg: BigNumberish[] = uint8ArrayToBigNumberishArray(message); | |
| const msgHash = hash.computeHashOnElements(msg); | |
| const signature: WeierstrassSignatureType = ec.starkCurve.sign(msgHash, this.privateKey); | |
| 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 | |
| // if (!signature.recovery) throw new Error("signature is missing required recovery component"); | |
| // @ts-ignore | |
| const recovery = signature.recovery.toString(16).padStart(2, "0"); // Convert recovery to hex string | |
| console.log("signature:=", signature); | |
| const rArray = Uint8Array.from(Buffer.from(r, "hex")); | |
| const sArray = Uint8Array.from(Buffer.from(s, "hex")); | |
| const recoveryArray = Uint8Array.from(Buffer.from(recovery, "hex")); | |
| // Concatenate the arrays | |
| const result = new Uint8Array(rArray.length + sArray.length + recoveryArray.length); | |
| result.set(rArray); | |
| result.set(sArray, rArray.length); | |
| result.set(recoveryArray, rArray.length + sArray.length); | |
| return result; | |
| } | |
| static async verify(_pk: Buffer, message: Uint8Array, _signature: Uint8Array, _opts?: any): Promise<boolean> { | |
| // generate message hash and signature | |
| const msg: BigNumberish[] = uint8ArrayToBigNumberishArray(message); | |
| const msgHash = hash.computeHashOnElements(msg); | |
| const fullPubKey = encode.addHexPrefix(encode.buf2hex(_pk)); | |
| // verify | |
| return ec.starkCurve.verify(_signature.slice(0, -1), msgHash, fullPubKey); | |
| } | |
| } | |
| // helper function to convert Uint8Array -> BigNumberishArray | |
| function uint8ArrayToBigNumberishArray(uint8Arr: Uint8Array): BigNumberish[] { | |
| const chunkSize = 31; // 252 bits = 31.5 bytes, but using 31 bytes for safety | |
| const bigNumberishArray: BigNumberish[] = []; | |
| for (let i = 0; i < uint8Arr.length; i += chunkSize) { | |
| // Extract a chunk of size 31 bytes | |
| const chunk = uint8Arr.slice(i, i + chunkSize); | |
| // Convert the chunk to a bigint | |
| let bigIntValue = BigInt(0); | |
| for (let j = 0; j < chunk.length; j++) { | |
| bigIntValue = (bigIntValue << BigInt(8)) + BigInt(chunk[j]); | |
| } | |
| bigNumberishArray.push(bigIntValue); | |
| } | |
| return bigNumberishArray; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment