@mysten/sui
Version:
Sui TypeScript API
1 lines • 15.4 kB
Source Map (JSON)
{"version":3,"file":"publickey.mjs","names":["bcs"],"sources":["../../src/multisig/publickey.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { fromBase64, toBase64 } from '@mysten/bcs';\nimport { blake2b } from '@noble/hashes/blake2.js';\nimport { bytesToHex } from '@noble/hashes/utils.js';\n\nimport { bcs } from '../bcs/index.js';\nimport type { Signer } from '../cryptography/keypair.js';\nimport { bytesEqual, PublicKey } from '../cryptography/publickey.js';\nimport {\n\tSIGNATURE_FLAG_TO_SCHEME,\n\tSIGNATURE_SCHEME_TO_FLAG,\n} from '../cryptography/signature-scheme.js';\nimport type { SignatureFlag, SignatureScheme } from '../cryptography/signature-scheme.js';\nimport { parseSerializedSignature } from '../cryptography/signature.js';\nimport { normalizeSuiAddress } from '../utils/sui-types.js';\nimport { publicKeyFromRawBytes } from '../verify/index.js';\nimport { toZkLoginPublicIdentifier } from '../zklogin/publickey.js';\nimport { MultiSigSigner } from './signer.js';\nimport type { ClientWithCoreApi } from '../client/core.js';\n\ntype CompressedSignature =\n\t| { ED25519: Uint8Array }\n\t| { Secp256k1: Uint8Array }\n\t| { Secp256r1: Uint8Array }\n\t| { ZkLogin: Uint8Array }\n\t| { Passkey: Uint8Array };\n\ntype PublicKeyEnum =\n\t| { ED25519: Uint8Array }\n\t| { Secp256k1: Uint8Array }\n\t| { Secp256r1: Uint8Array }\n\t| { ZkLogin: Uint8Array }\n\t| { Passkey: Uint8Array };\n\ntype PubkeyEnumWeightPair = {\n\tpubKey: PublicKeyEnum;\n\tweight: number;\n};\n\ntype MultiSigPublicKeyStruct = {\n\tpk_map: PubkeyEnumWeightPair[];\n\tthreshold: number;\n};\n\nexport type MultiSigStruct = {\n\tsigs: CompressedSignature[];\n\tbitmap: number;\n\tmultisig_pk: MultiSigPublicKeyStruct;\n};\n\ntype ParsedPartialMultiSigSignature = {\n\tsignatureScheme: SignatureScheme;\n\tsignature: Uint8Array;\n\tpublicKey: PublicKey;\n\tweight: number;\n};\n\nexport const MAX_SIGNER_IN_MULTISIG = 10;\nexport const MIN_SIGNER_IN_MULTISIG = 1;\n/**\n * A MultiSig public key\n */\nexport class MultiSigPublicKey extends PublicKey {\n\tprivate rawBytes: Uint8Array<ArrayBuffer>;\n\tprivate multisigPublicKey: MultiSigPublicKeyStruct;\n\tprivate publicKeys: {\n\t\tweight: number;\n\t\tpublicKey: PublicKey;\n\t}[];\n\t/**\n\t * Create a new MultiSigPublicKey object\n\t */\n\tconstructor(\n\t\t/**\n\t\t * MultiSig public key as buffer or base-64 encoded string\n\t\t */\n\t\tvalue: string | Uint8Array | MultiSigPublicKeyStruct,\n\t\toptions: { client?: ClientWithCoreApi } = {},\n\t) {\n\t\tsuper();\n\n\t\tif (typeof value === 'string') {\n\t\t\tthis.rawBytes = fromBase64(value);\n\n\t\t\tthis.multisigPublicKey = bcs.MultiSigPublicKey.parse(this.rawBytes);\n\t\t} else if (value instanceof Uint8Array) {\n\t\t\tthis.rawBytes = value as Uint8Array<ArrayBuffer>;\n\t\t\tthis.multisigPublicKey = bcs.MultiSigPublicKey.parse(this.rawBytes);\n\t\t} else {\n\t\t\tthis.multisigPublicKey = value;\n\t\t\tthis.rawBytes = bcs.MultiSigPublicKey.serialize(value).toBytes();\n\t\t}\n\t\tif (this.multisigPublicKey.threshold < 1) {\n\t\t\tthrow new Error('Invalid threshold');\n\t\t}\n\n\t\tconst seenPublicKeys = new Set<string>();\n\n\t\tthis.publicKeys = this.multisigPublicKey.pk_map.map(({ pubKey, weight }) => {\n\t\t\tconst [scheme, bytes] = Object.entries(pubKey).filter(([name]) => name !== '$kind')[0] as [\n\t\t\t\tSignatureScheme,\n\t\t\t\tUint8Array,\n\t\t\t];\n\t\t\tconst publicKeyStr = Uint8Array.from(bytes).toString();\n\n\t\t\tif (seenPublicKeys.has(publicKeyStr)) {\n\t\t\t\tthrow new Error(`Multisig does not support duplicate public keys`);\n\t\t\t}\n\t\t\tseenPublicKeys.add(publicKeyStr);\n\n\t\t\tif (weight < 1) {\n\t\t\t\tthrow new Error(`Invalid weight`);\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tpublicKey: publicKeyFromRawBytes(scheme, Uint8Array.from(bytes), options),\n\t\t\t\tweight,\n\t\t\t};\n\t\t});\n\n\t\tconst totalWeight = this.publicKeys.reduce((sum, { weight }) => sum + weight, 0);\n\n\t\tif (this.multisigPublicKey.threshold > totalWeight) {\n\t\t\tthrow new Error(`Unreachable threshold`);\n\t\t}\n\n\t\tif (this.publicKeys.length > MAX_SIGNER_IN_MULTISIG) {\n\t\t\tthrow new Error(`Max number of signers in a multisig is ${MAX_SIGNER_IN_MULTISIG}`);\n\t\t}\n\n\t\tif (this.publicKeys.length < MIN_SIGNER_IN_MULTISIG) {\n\t\t\tthrow new Error(`Min number of signers in a multisig is ${MIN_SIGNER_IN_MULTISIG}`);\n\t\t}\n\t}\n\t/**\n\t * \tA static method to create a new MultiSig publickey instance from a set of public keys and their associated weights pairs and threshold.\n\t */\n\n\tstatic fromPublicKeys({\n\t\tthreshold,\n\t\tpublicKeys,\n\t}: {\n\t\tthreshold: number;\n\t\tpublicKeys: { publicKey: PublicKey; weight: number }[];\n\t}) {\n\t\treturn new MultiSigPublicKey({\n\t\t\tpk_map: publicKeys.map(({ publicKey, weight }) => {\n\t\t\t\tconst scheme = SIGNATURE_FLAG_TO_SCHEME[publicKey.flag() as SignatureFlag];\n\n\t\t\t\treturn {\n\t\t\t\t\tpubKey: { [scheme]: publicKey.toRawBytes() } as PublicKeyEnum,\n\t\t\t\t\tweight,\n\t\t\t\t};\n\t\t\t}),\n\t\t\tthreshold,\n\t\t});\n\t}\n\n\t/**\n\t * Checks if two MultiSig public keys are equal\n\t */\n\toverride equals(publicKey: MultiSigPublicKey): boolean {\n\t\treturn super.equals(publicKey);\n\t}\n\n\t/**\n\t * Return the byte array representation of the MultiSig public key\n\t */\n\ttoRawBytes(): Uint8Array<ArrayBuffer> {\n\t\treturn this.rawBytes;\n\t}\n\n\tgetPublicKeys() {\n\t\treturn this.publicKeys;\n\t}\n\n\tgetThreshold() {\n\t\treturn this.multisigPublicKey.threshold;\n\t}\n\n\tgetSigner(...signers: [signer: Signer]) {\n\t\treturn new MultiSigSigner(this, signers);\n\t}\n\n\t/**\n\t * Return the Sui address associated with this MultiSig public key\n\t */\n\toverride toSuiAddress(): string {\n\t\t// max length = 1 flag byte + (max pk size + max weight size (u8)) * max signer size + 2 threshold bytes (u16)\n\t\tconst maxLength = 1 + (64 + 1) * MAX_SIGNER_IN_MULTISIG + 2;\n\t\tconst tmp = new Uint8Array(maxLength);\n\t\ttmp.set([SIGNATURE_SCHEME_TO_FLAG['MultiSig']]);\n\n\t\ttmp.set(bcs.u16().serialize(this.multisigPublicKey.threshold).toBytes(), 1);\n\t\t// The initial value 3 ensures that following data will be after the flag byte and threshold bytes\n\t\tlet i = 3;\n\t\tfor (const { publicKey, weight } of this.publicKeys) {\n\t\t\tconst bytes = publicKey.toSuiBytes();\n\t\t\ttmp.set(bytes, i);\n\t\t\ti += bytes.length;\n\t\t\ttmp.set([weight], i++);\n\t\t}\n\t\treturn normalizeSuiAddress(bytesToHex(blake2b(tmp.slice(0, i), { dkLen: 32 })));\n\t}\n\n\t/**\n\t * Return the Sui address associated with this MultiSig public key\n\t */\n\tflag(): number {\n\t\treturn SIGNATURE_SCHEME_TO_FLAG['MultiSig'];\n\t}\n\n\t/**\n\t * Verifies that the signature is valid for for the provided message\n\t */\n\tasync verify(message: Uint8Array, multisigSignature: string): Promise<boolean> {\n\t\t// Multisig verification only supports serialized signature\n\t\tconst parsed = parseSerializedSignature(multisigSignature);\n\n\t\tif (parsed.signatureScheme !== 'MultiSig') {\n\t\t\tthrow new Error('Invalid signature scheme');\n\t\t}\n\n\t\tconst { multisig } = parsed;\n\n\t\tlet signatureWeight = 0;\n\n\t\tif (\n\t\t\t!bytesEqual(\n\t\t\t\tbcs.MultiSigPublicKey.serialize(this.multisigPublicKey).toBytes(),\n\t\t\t\tbcs.MultiSigPublicKey.serialize(multisig.multisig_pk).toBytes(),\n\t\t\t)\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\n\t\tfor (const { publicKey, weight, signature } of parsePartialSignatures(multisig)) {\n\t\t\tif (!(await publicKey.verify(message, signature))) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tsignatureWeight += weight;\n\t\t}\n\n\t\treturn signatureWeight >= this.multisigPublicKey.threshold;\n\t}\n\n\t/**\n\t * Combines multiple partial signatures into a single multisig, ensuring that each public key signs only once\n\t * and that all the public keys involved are known and valid, and then serializes multisig into the standard format\n\t */\n\tcombinePartialSignatures(signatures: string[]): string {\n\t\tif (signatures.length > MAX_SIGNER_IN_MULTISIG) {\n\t\t\tthrow new Error(`Max number of signatures in a multisig is ${MAX_SIGNER_IN_MULTISIG}`);\n\t\t}\n\n\t\tlet bitmap = 0;\n\t\tconst compressedSignatures: CompressedSignature[] = new Array(signatures.length);\n\n\t\tfor (let i = 0; i < signatures.length; i++) {\n\t\t\tconst parsed = parseSerializedSignature(signatures[i]);\n\t\t\tif (parsed.signatureScheme === 'MultiSig') {\n\t\t\t\tthrow new Error('MultiSig is not supported inside MultiSig');\n\t\t\t}\n\n\t\t\tlet publicKey;\n\t\t\tif (parsed.signatureScheme === 'ZkLogin') {\n\t\t\t\tpublicKey = toZkLoginPublicIdentifier(parsed.zkLogin?.addressSeed, parsed.zkLogin?.iss, {\n\t\t\t\t\tlegacyAddress: false,\n\t\t\t\t}).toRawBytes();\n\t\t\t} else {\n\t\t\t\tpublicKey = parsed.publicKey;\n\t\t\t}\n\n\t\t\tcompressedSignatures[i] = {\n\t\t\t\t[parsed.signatureScheme]: parsed.signature,\n\t\t\t} as CompressedSignature;\n\n\t\t\tlet publicKeyIndex;\n\t\t\tfor (let j = 0; j < this.publicKeys.length; j++) {\n\t\t\t\tif (bytesEqual(publicKey, this.publicKeys[j].publicKey.toRawBytes())) {\n\t\t\t\t\tif (bitmap & (1 << j)) {\n\t\t\t\t\t\tthrow new Error('Received multiple signatures from the same public key');\n\t\t\t\t\t}\n\n\t\t\t\t\tpublicKeyIndex = j;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (publicKeyIndex === undefined) {\n\t\t\t\tthrow new Error('Received signature from unknown public key');\n\t\t\t}\n\n\t\t\tbitmap |= 1 << publicKeyIndex;\n\t\t}\n\n\t\tconst multisig: MultiSigStruct = {\n\t\t\tsigs: compressedSignatures,\n\t\t\tbitmap,\n\t\t\tmultisig_pk: this.multisigPublicKey,\n\t\t};\n\t\tconst bytes = bcs.MultiSig.serialize(multisig, { maxSize: 8192 }).toBytes();\n\t\tconst tmp = new Uint8Array(bytes.length + 1);\n\t\ttmp.set([SIGNATURE_SCHEME_TO_FLAG['MultiSig']]);\n\t\ttmp.set(bytes, 1);\n\t\treturn toBase64(tmp);\n\t}\n}\n\n/**\n * Parse multisig structure into an array of individual signatures: signature scheme, the actual individual signature, public key and its weight.\n */\nexport function parsePartialSignatures(\n\tmultisig: MultiSigStruct,\n\toptions: { client?: ClientWithCoreApi } = {},\n): ParsedPartialMultiSigSignature[] {\n\tconst res: ParsedPartialMultiSigSignature[] = new Array(multisig.sigs.length);\n\tfor (let i = 0; i < multisig.sigs.length; i++) {\n\t\tconst [signatureScheme, signature] = Object.entries(multisig.sigs[i]).filter(\n\t\t\t([name]) => name !== '$kind',\n\t\t)[0] as [SignatureScheme, Uint8Array];\n\t\tconst pkIndex = asIndices(multisig.bitmap).at(i)!;\n\t\tconst pair = multisig.multisig_pk.pk_map[pkIndex];\n\t\tconst pkBytes = Uint8Array.from(Object.values(pair.pubKey)[0]);\n\n\t\tif (signatureScheme === 'MultiSig') {\n\t\t\tthrow new Error('MultiSig is not supported inside MultiSig');\n\t\t}\n\n\t\tconst publicKey = publicKeyFromRawBytes(signatureScheme, pkBytes, options);\n\n\t\tres[i] = {\n\t\t\tsignatureScheme,\n\t\t\tsignature: Uint8Array.from(signature),\n\t\t\tpublicKey: publicKey,\n\t\t\tweight: pair.weight,\n\t\t};\n\t}\n\treturn res;\n}\n\nfunction asIndices(bitmap: number): Uint8Array {\n\tif (bitmap < 0 || bitmap > 1024) {\n\t\tthrow new Error('Invalid bitmap');\n\t}\n\tconst res: number[] = [];\n\tfor (let i = 0; i < 10; i++) {\n\t\tif ((bitmap & (1 << i)) !== 0) {\n\t\t\tres.push(i);\n\t\t}\n\t}\n\treturn Uint8Array.from(res);\n}\n"],"mappings":"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"}