From 8384490bb259459a7754675d9eee85625716f821 Mon Sep 17 00:00:00 2001 From: Jordan Gensler Date: Wed, 6 Sep 2023 10:43:38 -0700 Subject: [PATCH] Add method to get a ZK signature instead of relying on BCS (#13546) ## Description This will simplify a decent amount of the process. ## Test Plan How did you test the new or updated feature? --- If your changes are not user-facing and not a breaking change, you can skip the following section. Otherwise, please indicate what changed, and then add to the Release Notes section as highlighted during the release process. ### Type of Change (Check all that apply) - [ ] protocol change - [ ] user-visible impact - [ ] breaking change for a client SDKs - [ ] breaking change for FNs (FN binary must upgrade) - [ ] breaking change for validators or node operators (must upgrade binaries) - [ ] breaking change for on-chain data layout - [ ] necessitate either a data wipe or data migration ### Release notes --- .changeset/curly-lemons-act.md | 5 ++ .../src/background/accounts/zk/ZkAccount.ts | 22 ++------ sdk/zklogin/src/address.ts | 8 +-- sdk/zklogin/src/bcs.ts | 50 ++++++++++++++++++- sdk/zklogin/src/index.ts | 2 +- 5 files changed, 60 insertions(+), 27 deletions(-) create mode 100644 .changeset/curly-lemons-act.md diff --git a/.changeset/curly-lemons-act.md b/.changeset/curly-lemons-act.md new file mode 100644 index 0000000000000..6dd4cfefca8f5 --- /dev/null +++ b/.changeset/curly-lemons-act.md @@ -0,0 +1,5 @@ +--- +'@mysten/zklogin': patch +--- + +Remove BCS export and introduce new getZkSignature export. diff --git a/apps/wallet/src/background/accounts/zk/ZkAccount.ts b/apps/wallet/src/background/accounts/zk/ZkAccount.ts index f56bbf30904b2..f99dec4328c35 100644 --- a/apps/wallet/src/background/accounts/zk/ZkAccount.ts +++ b/apps/wallet/src/background/accounts/zk/ZkAccount.ts @@ -4,11 +4,9 @@ import { type SerializedSignature, type ExportedKeypair, - SIGNATURE_SCHEME_TO_FLAG, toSerializedSignature, } from '@mysten/sui.js/cryptography'; -import { fromB64, toB64 } from '@mysten/sui.js/utils'; -import { computeZkAddress, zkBcs } from '@mysten/zklogin'; +import { computeZkAddress, getZkSignature } from '@mysten/zklogin'; import { blake2b } from '@noble/hashes/blake2b'; import { decodeJwt } from 'jose'; import { getCurrentEpoch } from './current-epoch'; @@ -230,25 +228,13 @@ export class ZkAccount } const { ephemeralKeyPair, proofs, maxEpoch } = credentials; const keyPair = fromExportedKeypair(ephemeralKeyPair); + const userSignature = toSerializedSignature({ signature: await keyPair.sign(digest), signatureScheme: keyPair.getKeyScheme(), publicKey: keyPair.getPublicKey(), }); - const bytes = zkBcs - .ser( - 'ZkSignature', - { - inputs: proofs, - max_epoch: maxEpoch, - user_signature: fromB64(userSignature), - }, - { maxSize: 2048 }, - ) - .toBytes(); - const signatureBytes = new Uint8Array(bytes.length + 1); - signatureBytes.set([SIGNATURE_SCHEME_TO_FLAG['Zk']]); - signatureBytes.set(bytes, 1); - return toB64(signatureBytes); + + return getZkSignature({ inputs: proofs, maxEpoch, userSignature }); } } diff --git a/sdk/zklogin/src/address.ts b/sdk/zklogin/src/address.ts index fe1ca7e7b01ad..fce52fde906c5 100644 --- a/sdk/zklogin/src/address.ts +++ b/sdk/zklogin/src/address.ts @@ -11,13 +11,7 @@ import { genAddressSeed, toBufferBE } from './utils.js'; export function jwtToAddress(jwt: string, userSalt: bigint) { const decodedJWT = decodeJwt(jwt); - if ( - !decodedJWT.sub || - !decodedJWT.iss || - !decodedJWT.aud || - !decodedJWT.email || - typeof decodedJWT.email !== 'string' - ) { + if (!decodedJWT.sub || !decodedJWT.iss || !decodedJWT.aud) { throw new Error('Missing jwt data'); } diff --git a/sdk/zklogin/src/bcs.ts b/sdk/zklogin/src/bcs.ts index 897e3fbb18e24..c76e556e9a17b 100644 --- a/sdk/zklogin/src/bcs.ts +++ b/sdk/zklogin/src/bcs.ts @@ -1,7 +1,8 @@ // Copyright (c) Mysten Labs, Inc. // SPDX-License-Identifier: Apache-2.0 -import { BCS } from '@mysten/bcs'; +import { BCS, fromB64, toB64 } from '@mysten/bcs'; +import { SIGNATURE_SCHEME_TO_FLAG } from '@mysten/sui.js/cryptography'; import { bcs } from '@mysten/sui.js/bcs'; export const zkBcs = new BCS(bcs); @@ -17,6 +18,31 @@ zkBcs.registerStructType('ZkClaim', { index_mod_4: BCS.U8, }); +type Claim = { + name: string; + value_base64: string; + index_mod_4: number; +}; + +export interface ProofPoints { + pi_a: string[]; + pi_b: string[][]; + pi_c: string[]; +} + +export interface ZkSignatureInputs { + proof_points: ProofPoints; + address_seed: string; + claims: Claim[]; + header_base64: string; +} + +export interface ZkSignature { + inputs: ZkSignatureInputs; + maxEpoch: number; + userSignature: string | Uint8Array; +} + zkBcs.registerStructType('ZkSignature', { inputs: { proof_points: { @@ -31,3 +57,25 @@ zkBcs.registerStructType('ZkSignature', { max_epoch: BCS.U64, user_signature: [BCS.VECTOR, BCS.U8], }); + +function getZkSignatureBytes({ inputs, maxEpoch, userSignature }: ZkSignature) { + return zkBcs + .ser( + 'ZkSignature', + { + inputs, + max_epoch: maxEpoch, + user_signature: typeof userSignature === 'string' ? fromB64(userSignature) : userSignature, + }, + { maxSize: 2048 }, + ) + .toBytes(); +} + +export function getZkSignature({ inputs, maxEpoch, userSignature }: ZkSignature) { + const bytes = getZkSignatureBytes({ inputs, maxEpoch, userSignature }); + const signatureBytes = new Uint8Array(bytes.length + 1); + signatureBytes.set([SIGNATURE_SCHEME_TO_FLAG['Zk']]); + signatureBytes.set(bytes, 1); + return toB64(signatureBytes); +} diff --git a/sdk/zklogin/src/index.ts b/sdk/zklogin/src/index.ts index 652bbcaf03ae0..bf699cc400aa5 100644 --- a/sdk/zklogin/src/index.ts +++ b/sdk/zklogin/src/index.ts @@ -4,7 +4,7 @@ export { computeZkAddress, jwtToAddress } from './address.js'; export type { ComputeZKAddressOptions } from './address.js'; -export { zkBcs } from './bcs.js'; +export { getZkSignature } from './bcs.js'; export { poseidonHash } from './poseidon.js';