@mysten/sui 1.15.1 → 1.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +40 -0
- package/dist/cjs/version.d.ts +2 -2
- package/dist/cjs/version.js +2 -2
- package/dist/cjs/version.js.map +1 -1
- package/dist/cjs/zklogin/address.d.ts +16 -1
- package/dist/cjs/zklogin/address.js +55 -3
- package/dist/cjs/zklogin/address.js.map +2 -2
- package/dist/cjs/zklogin/index.d.ts +5 -2
- package/dist/cjs/zklogin/index.js +10 -0
- package/dist/cjs/zklogin/index.js.map +2 -2
- package/dist/cjs/zklogin/nonce.d.ts +4 -0
- package/dist/cjs/zklogin/nonce.js +54 -0
- package/dist/cjs/zklogin/nonce.js.map +7 -0
- package/dist/cjs/zklogin/poseidon.d.ts +2 -0
- package/dist/cjs/zklogin/poseidon.js +63 -0
- package/dist/cjs/zklogin/poseidon.js.map +7 -0
- package/dist/cjs/zklogin/publickey.d.ts +2 -0
- package/dist/cjs/zklogin/publickey.js +33 -3
- package/dist/cjs/zklogin/publickey.js.map +3 -3
- package/dist/cjs/zklogin/utils.d.ts +13 -0
- package/dist/cjs/zklogin/utils.js +44 -0
- package/dist/cjs/zklogin/utils.js.map +2 -2
- package/dist/esm/version.d.ts +2 -2
- package/dist/esm/version.js +2 -2
- package/dist/esm/version.js.map +1 -1
- package/dist/esm/zklogin/address.d.ts +16 -1
- package/dist/esm/zklogin/address.js +56 -4
- package/dist/esm/zklogin/address.js.map +2 -2
- package/dist/esm/zklogin/index.d.ts +5 -2
- package/dist/esm/zklogin/index.js +18 -2
- package/dist/esm/zklogin/index.js.map +2 -2
- package/dist/esm/zklogin/nonce.d.ts +4 -0
- package/dist/esm/zklogin/nonce.js +34 -0
- package/dist/esm/zklogin/nonce.js.map +7 -0
- package/dist/esm/zklogin/poseidon.d.ts +2 -0
- package/dist/esm/zklogin/poseidon.js +60 -0
- package/dist/esm/zklogin/poseidon.js.map +7 -0
- package/dist/esm/zklogin/publickey.d.ts +2 -0
- package/dist/esm/zklogin/publickey.js +34 -4
- package/dist/esm/zklogin/publickey.js.map +2 -2
- package/dist/esm/zklogin/utils.d.ts +13 -0
- package/dist/esm/zklogin/utils.js +44 -0
- package/dist/esm/zklogin/utils.js.map +2 -2
- package/dist/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -2
- package/src/version.ts +2 -2
- package/src/zklogin/address.ts +81 -3
- package/src/zklogin/index.ts +11 -2
- package/src/zklogin/nonce.ts +38 -0
- package/src/zklogin/poseidon.ts +64 -0
- package/src/zklogin/publickey.ts +42 -4
- package/src/zklogin/utils.ts +72 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/zklogin/utils.ts"],
|
|
4
|
-
"sourcesContent": ["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { hexToBytes } from '@noble/hashes/utils';\n\nfunction findFirstNonZeroIndex(bytes: Uint8Array) {\n\tfor (let i = 0; i < bytes.length; i++) {\n\t\tif (bytes[i] !== 0) {\n\t\t\treturn i;\n\t\t}\n\t}\n\n\treturn -1;\n}\n\n// Derive bytearray from num where the bytearray is padded to the left with 0s to the specified width.\nexport function toPaddedBigEndianBytes(num: bigint, width: number): Uint8Array {\n\tconst hex = num.toString(16);\n\treturn hexToBytes(hex.padStart(width * 2, '0').slice(-width * 2));\n}\n\n// Derive bytearray from num where the bytearray is not padded with 0.\nexport function toBigEndianBytes(num: bigint, width: number): Uint8Array {\n\tconst bytes = toPaddedBigEndianBytes(num, width);\n\n\tconst firstNonZeroIndex = findFirstNonZeroIndex(bytes);\n\n\tif (firstNonZeroIndex === -1) {\n\t\treturn new Uint8Array([0]);\n\t}\n\n\treturn bytes.slice(firstNonZeroIndex);\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,mBAA2B;
|
|
4
|
+
"sourcesContent": ["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { hexToBytes } from '@noble/hashes/utils';\n\nimport type { PublicKey } from '../cryptography/publickey.js';\nimport { poseidonHash } from './poseidon.js';\n\nconst MAX_KEY_CLAIM_NAME_LENGTH = 32;\nconst MAX_KEY_CLAIM_VALUE_LENGTH = 115;\nconst MAX_AUD_VALUE_LENGTH = 145;\nconst PACK_WIDTH = 248;\n\nfunction findFirstNonZeroIndex(bytes: Uint8Array) {\n\tfor (let i = 0; i < bytes.length; i++) {\n\t\tif (bytes[i] !== 0) {\n\t\t\treturn i;\n\t\t}\n\t}\n\n\treturn -1;\n}\n\n// Derive bytearray from num where the bytearray is padded to the left with 0s to the specified width.\nexport function toPaddedBigEndianBytes(num: bigint, width: number): Uint8Array {\n\tconst hex = num.toString(16);\n\treturn hexToBytes(hex.padStart(width * 2, '0').slice(-width * 2));\n}\n\n// Derive bytearray from num where the bytearray is not padded with 0.\nexport function toBigEndianBytes(num: bigint, width: number): Uint8Array {\n\tconst bytes = toPaddedBigEndianBytes(num, width);\n\n\tconst firstNonZeroIndex = findFirstNonZeroIndex(bytes);\n\n\tif (firstNonZeroIndex === -1) {\n\t\treturn new Uint8Array([0]);\n\t}\n\n\treturn bytes.slice(firstNonZeroIndex);\n}\n\nexport function getExtendedEphemeralPublicKey(publicKey: PublicKey) {\n\treturn publicKey.toSuiPublicKey();\n}\n\n/**\n * Splits an array into chunks of size chunk_size. If the array is not evenly\n * divisible by chunk_size, the first chunk will be smaller than chunk_size.\n *\n * E.g., arrayChunk([1, 2, 3, 4, 5], 2) => [[1], [2, 3], [4, 5]]\n *\n * Note: Can be made more efficient by avoiding the reverse() calls.\n */\nexport function chunkArray<T>(array: T[], chunk_size: number): T[][] {\n\tconst chunks = Array(Math.ceil(array.length / chunk_size));\n\tconst revArray = array.reverse();\n\tfor (let i = 0; i < chunks.length; i++) {\n\t\tchunks[i] = revArray.slice(i * chunk_size, (i + 1) * chunk_size).reverse();\n\t}\n\treturn chunks.reverse();\n}\n\nfunction bytesBEToBigInt(bytes: number[]): bigint {\n\tconst hex = bytes.map((b) => b.toString(16).padStart(2, '0')).join('');\n\tif (hex.length === 0) {\n\t\treturn BigInt(0);\n\t}\n\treturn BigInt('0x' + hex);\n}\n\n// hashes an ASCII string to a field element\nexport function hashASCIIStrToField(str: string, maxSize: number) {\n\tif (str.length > maxSize) {\n\t\tthrow new Error(`String ${str} is longer than ${maxSize} chars`);\n\t}\n\n\t// Note: Padding with zeroes is safe because we are only using this function to map human-readable sequence of bytes.\n\t// So the ASCII values of those characters will never be zero (null character).\n\tconst strPadded = str\n\t\t.padEnd(maxSize, String.fromCharCode(0))\n\t\t.split('')\n\t\t.map((c) => c.charCodeAt(0));\n\n\tconst chunkSize = PACK_WIDTH / 8;\n\tconst packed = chunkArray(strPadded, chunkSize).map((chunk) => bytesBEToBigInt(chunk));\n\treturn poseidonHash(packed);\n}\n\nexport function genAddressSeed(\n\tsalt: string | bigint,\n\tname: string,\n\tvalue: string,\n\taud: string,\n\tmax_name_length = MAX_KEY_CLAIM_NAME_LENGTH,\n\tmax_value_length = MAX_KEY_CLAIM_VALUE_LENGTH,\n\tmax_aud_length = MAX_AUD_VALUE_LENGTH,\n): bigint {\n\treturn poseidonHash([\n\t\thashASCIIStrToField(name, max_name_length),\n\t\thashASCIIStrToField(value, max_value_length),\n\t\thashASCIIStrToField(aud, max_aud_length),\n\t\tposeidonHash([BigInt(salt)]),\n\t]);\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,mBAA2B;AAG3B,sBAA6B;AAE7B,MAAM,4BAA4B;AAClC,MAAM,6BAA6B;AACnC,MAAM,uBAAuB;AAC7B,MAAM,aAAa;AAEnB,SAAS,sBAAsB,OAAmB;AACjD,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACtC,QAAI,MAAM,CAAC,MAAM,GAAG;AACnB,aAAO;AAAA,IACR;AAAA,EACD;AAEA,SAAO;AACR;AAGO,SAAS,uBAAuB,KAAa,OAA2B;AAC9E,QAAM,MAAM,IAAI,SAAS,EAAE;AAC3B,aAAO,yBAAW,IAAI,SAAS,QAAQ,GAAG,GAAG,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;AACjE;AAGO,SAAS,iBAAiB,KAAa,OAA2B;AACxE,QAAM,QAAQ,uBAAuB,KAAK,KAAK;AAE/C,QAAM,oBAAoB,sBAAsB,KAAK;AAErD,MAAI,sBAAsB,IAAI;AAC7B,WAAO,IAAI,WAAW,CAAC,CAAC,CAAC;AAAA,EAC1B;AAEA,SAAO,MAAM,MAAM,iBAAiB;AACrC;AAEO,SAAS,8BAA8B,WAAsB;AACnE,SAAO,UAAU,eAAe;AACjC;AAUO,SAAS,WAAc,OAAY,YAA2B;AACpE,QAAM,SAAS,MAAM,KAAK,KAAK,MAAM,SAAS,UAAU,CAAC;AACzD,QAAM,WAAW,MAAM,QAAQ;AAC/B,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACvC,WAAO,CAAC,IAAI,SAAS,MAAM,IAAI,aAAa,IAAI,KAAK,UAAU,EAAE,QAAQ;AAAA,EAC1E;AACA,SAAO,OAAO,QAAQ;AACvB;AAEA,SAAS,gBAAgB,OAAyB;AACjD,QAAM,MAAM,MAAM,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EAAE,KAAK,EAAE;AACrE,MAAI,IAAI,WAAW,GAAG;AACrB,WAAO,OAAO,CAAC;AAAA,EAChB;AACA,SAAO,OAAO,OAAO,GAAG;AACzB;AAGO,SAAS,oBAAoB,KAAa,SAAiB;AACjE,MAAI,IAAI,SAAS,SAAS;AACzB,UAAM,IAAI,MAAM,UAAU,GAAG,mBAAmB,OAAO,QAAQ;AAAA,EAChE;AAIA,QAAM,YAAY,IAChB,OAAO,SAAS,OAAO,aAAa,CAAC,CAAC,EACtC,MAAM,EAAE,EACR,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;AAE5B,QAAM,YAAY,aAAa;AAC/B,QAAM,SAAS,WAAW,WAAW,SAAS,EAAE,IAAI,CAAC,UAAU,gBAAgB,KAAK,CAAC;AACrF,aAAO,8BAAa,MAAM;AAC3B;AAEO,SAAS,eACf,MACA,MACA,OACA,KACA,kBAAkB,2BAClB,mBAAmB,4BACnB,iBAAiB,sBACR;AACT,aAAO,8BAAa;AAAA,IACnB,oBAAoB,MAAM,eAAe;AAAA,IACzC,oBAAoB,OAAO,gBAAgB;AAAA,IAC3C,oBAAoB,KAAK,cAAc;AAAA,QACvC,8BAAa,CAAC,OAAO,IAAI,CAAC,CAAC;AAAA,EAC5B,CAAC;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/esm/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const PACKAGE_VERSION = "1.
|
|
2
|
-
export declare const TARGETED_RPC_VERSION = "1.
|
|
1
|
+
export declare const PACKAGE_VERSION = "1.16.1";
|
|
2
|
+
export declare const TARGETED_RPC_VERSION = "1.40.0";
|
package/dist/esm/version.js
CHANGED
package/dist/esm/version.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/version.ts"],
|
|
4
|
-
"sourcesContent": ["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\n// This file is generated by genversion.mjs. Do not edit it directly.\n\nexport const PACKAGE_VERSION = '1.
|
|
4
|
+
"sourcesContent": ["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\n// This file is generated by genversion.mjs. Do not edit it directly.\n\nexport const PACKAGE_VERSION = '1.16.1';\nexport const TARGETED_RPC_VERSION = '1.40.0';\n"],
|
|
5
5
|
"mappings": "AAKO,MAAM,kBAAkB;AACxB,MAAM,uBAAuB;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1 +1,16 @@
|
|
|
1
|
-
export declare function computeZkLoginAddressFromSeed(addressSeed: bigint, iss: string
|
|
1
|
+
export declare function computeZkLoginAddressFromSeed(addressSeed: bigint, iss: string,
|
|
2
|
+
/** TODO: This default should be changed in the next major release */
|
|
3
|
+
legacyAddress?: boolean): string;
|
|
4
|
+
export declare const MAX_HEADER_LEN_B64 = 248;
|
|
5
|
+
export declare const MAX_PADDED_UNSIGNED_JWT_LEN: number;
|
|
6
|
+
export declare function lengthChecks(jwt: string): void;
|
|
7
|
+
export declare function jwtToAddress(jwt: string, userSalt: string | bigint, legacyAddress?: boolean): string;
|
|
8
|
+
export interface ComputeZkLoginAddressOptions {
|
|
9
|
+
claimName: string;
|
|
10
|
+
claimValue: string;
|
|
11
|
+
userSalt: string | bigint;
|
|
12
|
+
iss: string;
|
|
13
|
+
aud: string;
|
|
14
|
+
legacyAddress?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export declare function computeZkLoginAddress({ claimName, claimValue, iss, aud, userSalt, legacyAddress, }: ComputeZkLoginAddressOptions): string;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { blake2b } from "@noble/hashes/blake2b";
|
|
2
2
|
import { bytesToHex } from "@noble/hashes/utils";
|
|
3
|
+
import { decodeJwt } from "jose";
|
|
3
4
|
import { SIGNATURE_SCHEME_TO_FLAG } from "../cryptography/signature-scheme.js";
|
|
4
5
|
import { normalizeSuiAddress, SUI_ADDRESS_LENGTH } from "../utils/index.js";
|
|
5
|
-
import { toBigEndianBytes } from "./utils.js";
|
|
6
|
-
function computeZkLoginAddressFromSeed(addressSeed, iss) {
|
|
7
|
-
const addressSeedBytesBigEndian = toBigEndianBytes(addressSeed, 32);
|
|
6
|
+
import { genAddressSeed, toBigEndianBytes, toPaddedBigEndianBytes } from "./utils.js";
|
|
7
|
+
function computeZkLoginAddressFromSeed(addressSeed, iss, legacyAddress = true) {
|
|
8
|
+
const addressSeedBytesBigEndian = legacyAddress ? toBigEndianBytes(addressSeed, 32) : toPaddedBigEndianBytes(addressSeed, 32);
|
|
8
9
|
if (iss === "accounts.google.com") {
|
|
9
10
|
iss = "https://accounts.google.com";
|
|
10
11
|
}
|
|
@@ -18,7 +19,58 @@ function computeZkLoginAddressFromSeed(addressSeed, iss) {
|
|
|
18
19
|
bytesToHex(blake2b(tmp, { dkLen: 32 })).slice(0, SUI_ADDRESS_LENGTH * 2)
|
|
19
20
|
);
|
|
20
21
|
}
|
|
22
|
+
const MAX_HEADER_LEN_B64 = 248;
|
|
23
|
+
const MAX_PADDED_UNSIGNED_JWT_LEN = 64 * 25;
|
|
24
|
+
function lengthChecks(jwt) {
|
|
25
|
+
const [header, payload] = jwt.split(".");
|
|
26
|
+
if (header.length > MAX_HEADER_LEN_B64) {
|
|
27
|
+
throw new Error(`Header is too long`);
|
|
28
|
+
}
|
|
29
|
+
const L = (header.length + 1 + payload.length) * 8;
|
|
30
|
+
const K = (512 + 448 - (L % 512 + 1)) % 512;
|
|
31
|
+
const padded_unsigned_jwt_len = (L + 1 + K + 64) / 8;
|
|
32
|
+
if (padded_unsigned_jwt_len > MAX_PADDED_UNSIGNED_JWT_LEN) {
|
|
33
|
+
throw new Error(`JWT is too long`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function jwtToAddress(jwt, userSalt, legacyAddress = false) {
|
|
37
|
+
lengthChecks(jwt);
|
|
38
|
+
const decodedJWT = decodeJwt(jwt);
|
|
39
|
+
if (!decodedJWT.sub || !decodedJWT.iss || !decodedJWT.aud) {
|
|
40
|
+
throw new Error("Missing jwt data");
|
|
41
|
+
}
|
|
42
|
+
if (Array.isArray(decodedJWT.aud)) {
|
|
43
|
+
throw new Error("Not supported aud. Aud is an array, string was expected.");
|
|
44
|
+
}
|
|
45
|
+
return computeZkLoginAddress({
|
|
46
|
+
userSalt,
|
|
47
|
+
claimName: "sub",
|
|
48
|
+
claimValue: decodedJWT.sub,
|
|
49
|
+
aud: decodedJWT.aud,
|
|
50
|
+
iss: decodedJWT.iss,
|
|
51
|
+
legacyAddress
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
function computeZkLoginAddress({
|
|
55
|
+
claimName,
|
|
56
|
+
claimValue,
|
|
57
|
+
iss,
|
|
58
|
+
aud,
|
|
59
|
+
userSalt,
|
|
60
|
+
legacyAddress = false
|
|
61
|
+
}) {
|
|
62
|
+
return computeZkLoginAddressFromSeed(
|
|
63
|
+
genAddressSeed(userSalt, claimName, claimValue, aud),
|
|
64
|
+
iss,
|
|
65
|
+
legacyAddress
|
|
66
|
+
);
|
|
67
|
+
}
|
|
21
68
|
export {
|
|
22
|
-
|
|
69
|
+
MAX_HEADER_LEN_B64,
|
|
70
|
+
MAX_PADDED_UNSIGNED_JWT_LEN,
|
|
71
|
+
computeZkLoginAddress,
|
|
72
|
+
computeZkLoginAddressFromSeed,
|
|
73
|
+
jwtToAddress,
|
|
74
|
+
lengthChecks
|
|
23
75
|
};
|
|
24
76
|
//# sourceMappingURL=address.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/zklogin/address.ts"],
|
|
4
|
-
"sourcesContent": ["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { blake2b } from '@noble/hashes/blake2b';\nimport { bytesToHex } from '@noble/hashes/utils';\n\nimport { SIGNATURE_SCHEME_TO_FLAG } from '../cryptography/signature-scheme.js';\nimport { normalizeSuiAddress, SUI_ADDRESS_LENGTH } from '../utils/index.js';\nimport { toBigEndianBytes } from './utils.js';\n\nexport function computeZkLoginAddressFromSeed(
|
|
5
|
-
"mappings": "AAGA,SAAS,eAAe;AACxB,SAAS,kBAAkB;
|
|
4
|
+
"sourcesContent": ["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { blake2b } from '@noble/hashes/blake2b';\nimport { bytesToHex } from '@noble/hashes/utils';\nimport { decodeJwt } from 'jose';\n\nimport { SIGNATURE_SCHEME_TO_FLAG } from '../cryptography/signature-scheme.js';\nimport { normalizeSuiAddress, SUI_ADDRESS_LENGTH } from '../utils/index.js';\nimport { genAddressSeed, toBigEndianBytes, toPaddedBigEndianBytes } from './utils.js';\n\nexport function computeZkLoginAddressFromSeed(\n\taddressSeed: bigint,\n\tiss: string,\n\t/** TODO: This default should be changed in the next major release */\n\tlegacyAddress = true,\n) {\n\tconst addressSeedBytesBigEndian = legacyAddress\n\t\t? toBigEndianBytes(addressSeed, 32)\n\t\t: toPaddedBigEndianBytes(addressSeed, 32);\n\tif (iss === 'accounts.google.com') {\n\t\tiss = 'https://accounts.google.com';\n\t}\n\tconst addressParamBytes = new TextEncoder().encode(iss);\n\tconst tmp = new Uint8Array(2 + addressSeedBytesBigEndian.length + addressParamBytes.length);\n\n\ttmp.set([SIGNATURE_SCHEME_TO_FLAG.ZkLogin]);\n\ttmp.set([addressParamBytes.length], 1);\n\ttmp.set(addressParamBytes, 2);\n\ttmp.set(addressSeedBytesBigEndian, 2 + addressParamBytes.length);\n\n\treturn normalizeSuiAddress(\n\t\tbytesToHex(blake2b(tmp, { dkLen: 32 })).slice(0, SUI_ADDRESS_LENGTH * 2),\n\t);\n}\n\nexport const MAX_HEADER_LEN_B64 = 248;\nexport const MAX_PADDED_UNSIGNED_JWT_LEN = 64 * 25;\n\nexport function lengthChecks(jwt: string) {\n\tconst [header, payload] = jwt.split('.');\n\t/// Is the header small enough\n\tif (header.length > MAX_HEADER_LEN_B64) {\n\t\tthrow new Error(`Header is too long`);\n\t}\n\n\t/// Is the combined length of (header, payload, SHA2 padding) small enough?\n\t// unsigned_jwt = header + '.' + payload;\n\tconst L = (header.length + 1 + payload.length) * 8;\n\tconst K = (512 + 448 - ((L % 512) + 1)) % 512;\n\n\t// The SHA2 padding is 1 followed by K zeros, followed by the length of the message\n\tconst padded_unsigned_jwt_len = (L + 1 + K + 64) / 8;\n\n\t// The padded unsigned JWT must be less than the max_padded_unsigned_jwt_len\n\tif (padded_unsigned_jwt_len > MAX_PADDED_UNSIGNED_JWT_LEN) {\n\t\tthrow new Error(`JWT is too long`);\n\t}\n}\n\nexport function jwtToAddress(jwt: string, userSalt: string | bigint, legacyAddress = false) {\n\tlengthChecks(jwt);\n\n\tconst decodedJWT = decodeJwt(jwt);\n\tif (!decodedJWT.sub || !decodedJWT.iss || !decodedJWT.aud) {\n\t\tthrow new Error('Missing jwt data');\n\t}\n\n\tif (Array.isArray(decodedJWT.aud)) {\n\t\tthrow new Error('Not supported aud. Aud is an array, string was expected.');\n\t}\n\n\treturn computeZkLoginAddress({\n\t\tuserSalt,\n\t\tclaimName: 'sub',\n\t\tclaimValue: decodedJWT.sub,\n\t\taud: decodedJWT.aud,\n\t\tiss: decodedJWT.iss,\n\t\tlegacyAddress,\n\t});\n}\n\nexport interface ComputeZkLoginAddressOptions {\n\tclaimName: string;\n\tclaimValue: string;\n\tuserSalt: string | bigint;\n\tiss: string;\n\taud: string;\n\tlegacyAddress?: boolean;\n}\n\nexport function computeZkLoginAddress({\n\tclaimName,\n\tclaimValue,\n\tiss,\n\taud,\n\tuserSalt,\n\tlegacyAddress = false,\n}: ComputeZkLoginAddressOptions) {\n\treturn computeZkLoginAddressFromSeed(\n\t\tgenAddressSeed(userSalt, claimName, claimValue, aud),\n\t\tiss,\n\t\tlegacyAddress,\n\t);\n}\n"],
|
|
5
|
+
"mappings": "AAGA,SAAS,eAAe;AACxB,SAAS,kBAAkB;AAC3B,SAAS,iBAAiB;AAE1B,SAAS,gCAAgC;AACzC,SAAS,qBAAqB,0BAA0B;AACxD,SAAS,gBAAgB,kBAAkB,8BAA8B;AAElE,SAAS,8BACf,aACA,KAEA,gBAAgB,MACf;AACD,QAAM,4BAA4B,gBAC/B,iBAAiB,aAAa,EAAE,IAChC,uBAAuB,aAAa,EAAE;AACzC,MAAI,QAAQ,uBAAuB;AAClC,UAAM;AAAA,EACP;AACA,QAAM,oBAAoB,IAAI,YAAY,EAAE,OAAO,GAAG;AACtD,QAAM,MAAM,IAAI,WAAW,IAAI,0BAA0B,SAAS,kBAAkB,MAAM;AAE1F,MAAI,IAAI,CAAC,yBAAyB,OAAO,CAAC;AAC1C,MAAI,IAAI,CAAC,kBAAkB,MAAM,GAAG,CAAC;AACrC,MAAI,IAAI,mBAAmB,CAAC;AAC5B,MAAI,IAAI,2BAA2B,IAAI,kBAAkB,MAAM;AAE/D,SAAO;AAAA,IACN,WAAW,QAAQ,KAAK,EAAE,OAAO,GAAG,CAAC,CAAC,EAAE,MAAM,GAAG,qBAAqB,CAAC;AAAA,EACxE;AACD;AAEO,MAAM,qBAAqB;AAC3B,MAAM,8BAA8B,KAAK;AAEzC,SAAS,aAAa,KAAa;AACzC,QAAM,CAAC,QAAQ,OAAO,IAAI,IAAI,MAAM,GAAG;AAEvC,MAAI,OAAO,SAAS,oBAAoB;AACvC,UAAM,IAAI,MAAM,oBAAoB;AAAA,EACrC;AAIA,QAAM,KAAK,OAAO,SAAS,IAAI,QAAQ,UAAU;AACjD,QAAM,KAAK,MAAM,OAAQ,IAAI,MAAO,MAAM;AAG1C,QAAM,2BAA2B,IAAI,IAAI,IAAI,MAAM;AAGnD,MAAI,0BAA0B,6BAA6B;AAC1D,UAAM,IAAI,MAAM,iBAAiB;AAAA,EAClC;AACD;AAEO,SAAS,aAAa,KAAa,UAA2B,gBAAgB,OAAO;AAC3F,eAAa,GAAG;AAEhB,QAAM,aAAa,UAAU,GAAG;AAChC,MAAI,CAAC,WAAW,OAAO,CAAC,WAAW,OAAO,CAAC,WAAW,KAAK;AAC1D,UAAM,IAAI,MAAM,kBAAkB;AAAA,EACnC;AAEA,MAAI,MAAM,QAAQ,WAAW,GAAG,GAAG;AAClC,UAAM,IAAI,MAAM,0DAA0D;AAAA,EAC3E;AAEA,SAAO,sBAAsB;AAAA,IAC5B;AAAA,IACA,WAAW;AAAA,IACX,YAAY,WAAW;AAAA,IACvB,KAAK,WAAW;AAAA,IAChB,KAAK,WAAW;AAAA,IAChB;AAAA,EACD,CAAC;AACF;AAWO,SAAS,sBAAsB;AAAA,EACrC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,gBAAgB;AACjB,GAAiC;AAChC,SAAO;AAAA,IACN,eAAe,UAAU,WAAW,YAAY,GAAG;AAAA,IACnD;AAAA,IACA;AAAA,EACD;AACD;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
export { getZkLoginSignature, parseZkLoginSignature } from './signature.js';
|
|
2
|
-
export { toBigEndianBytes, toPaddedBigEndianBytes } from './utils.js';
|
|
3
|
-
export { computeZkLoginAddressFromSeed } from './address.js';
|
|
2
|
+
export { toBigEndianBytes, toPaddedBigEndianBytes, hashASCIIStrToField, genAddressSeed, getExtendedEphemeralPublicKey, } from './utils.js';
|
|
3
|
+
export { computeZkLoginAddressFromSeed, computeZkLoginAddress, jwtToAddress } from './address.js';
|
|
4
|
+
export type { ComputeZkLoginAddressOptions } from './address.js';
|
|
4
5
|
export { toZkLoginPublicIdentifier, ZkLoginPublicIdentifier } from './publickey.js';
|
|
5
6
|
export type { ZkLoginSignatureInputs } from './bcs.js';
|
|
7
|
+
export { poseidonHash } from './poseidon.js';
|
|
8
|
+
export { generateNonce, generateRandomness } from './nonce.js';
|
|
@@ -1,12 +1,28 @@
|
|
|
1
1
|
import { getZkLoginSignature, parseZkLoginSignature } from "./signature.js";
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import {
|
|
3
|
+
toBigEndianBytes,
|
|
4
|
+
toPaddedBigEndianBytes,
|
|
5
|
+
hashASCIIStrToField,
|
|
6
|
+
genAddressSeed,
|
|
7
|
+
getExtendedEphemeralPublicKey
|
|
8
|
+
} from "./utils.js";
|
|
9
|
+
import { computeZkLoginAddressFromSeed, computeZkLoginAddress, jwtToAddress } from "./address.js";
|
|
4
10
|
import { toZkLoginPublicIdentifier, ZkLoginPublicIdentifier } from "./publickey.js";
|
|
11
|
+
import { poseidonHash } from "./poseidon.js";
|
|
12
|
+
import { generateNonce, generateRandomness } from "./nonce.js";
|
|
5
13
|
export {
|
|
6
14
|
ZkLoginPublicIdentifier,
|
|
15
|
+
computeZkLoginAddress,
|
|
7
16
|
computeZkLoginAddressFromSeed,
|
|
17
|
+
genAddressSeed,
|
|
18
|
+
generateNonce,
|
|
19
|
+
generateRandomness,
|
|
20
|
+
getExtendedEphemeralPublicKey,
|
|
8
21
|
getZkLoginSignature,
|
|
22
|
+
hashASCIIStrToField,
|
|
23
|
+
jwtToAddress,
|
|
9
24
|
parseZkLoginSignature,
|
|
25
|
+
poseidonHash,
|
|
10
26
|
toBigEndianBytes,
|
|
11
27
|
toPaddedBigEndianBytes,
|
|
12
28
|
toZkLoginPublicIdentifier
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/zklogin/index.ts"],
|
|
4
|
-
"sourcesContent": ["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nexport { getZkLoginSignature, parseZkLoginSignature } from './signature.js';\nexport {
|
|
5
|
-
"mappings": "AAGA,SAAS,qBAAqB,6BAA6B;AAC3D,
|
|
4
|
+
"sourcesContent": ["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nexport { getZkLoginSignature, parseZkLoginSignature } from './signature.js';\nexport {\n\ttoBigEndianBytes,\n\ttoPaddedBigEndianBytes,\n\thashASCIIStrToField,\n\tgenAddressSeed,\n\tgetExtendedEphemeralPublicKey,\n} from './utils.js';\nexport { computeZkLoginAddressFromSeed, computeZkLoginAddress, jwtToAddress } from './address.js';\nexport type { ComputeZkLoginAddressOptions } from './address.js';\nexport { toZkLoginPublicIdentifier, ZkLoginPublicIdentifier } from './publickey.js';\nexport type { ZkLoginSignatureInputs } from './bcs.js';\nexport { poseidonHash } from './poseidon.js';\nexport { generateNonce, generateRandomness } from './nonce.js';\n"],
|
|
5
|
+
"mappings": "AAGA,SAAS,qBAAqB,6BAA6B;AAC3D;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP,SAAS,+BAA+B,uBAAuB,oBAAoB;AAEnF,SAAS,2BAA2B,+BAA+B;AAEnE,SAAS,oBAAoB;AAC7B,SAAS,eAAe,0BAA0B;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { PublicKey } from '../cryptography/publickey.js';
|
|
2
|
+
export declare const NONCE_LENGTH = 27;
|
|
3
|
+
export declare function generateRandomness(): string;
|
|
4
|
+
export declare function generateNonce(publicKey: PublicKey, maxEpoch: number, randomness: bigint | string): string;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { toHex } from "@mysten/bcs";
|
|
2
|
+
import { randomBytes } from "@noble/hashes/utils";
|
|
3
|
+
import { base64url } from "jose";
|
|
4
|
+
import { poseidonHash } from "./poseidon.js";
|
|
5
|
+
import { toPaddedBigEndianBytes } from "./utils.js";
|
|
6
|
+
const NONCE_LENGTH = 27;
|
|
7
|
+
function toBigIntBE(bytes) {
|
|
8
|
+
const hex = toHex(bytes);
|
|
9
|
+
if (hex.length === 0) {
|
|
10
|
+
return BigInt(0);
|
|
11
|
+
}
|
|
12
|
+
return BigInt(`0x${hex}`);
|
|
13
|
+
}
|
|
14
|
+
function generateRandomness() {
|
|
15
|
+
return String(toBigIntBE(randomBytes(16)));
|
|
16
|
+
}
|
|
17
|
+
function generateNonce(publicKey, maxEpoch, randomness) {
|
|
18
|
+
const publicKeyBytes = toBigIntBE(publicKey.toSuiBytes());
|
|
19
|
+
const eph_public_key_0 = publicKeyBytes / 2n ** 128n;
|
|
20
|
+
const eph_public_key_1 = publicKeyBytes % 2n ** 128n;
|
|
21
|
+
const bigNum = poseidonHash([eph_public_key_0, eph_public_key_1, maxEpoch, BigInt(randomness)]);
|
|
22
|
+
const Z = toPaddedBigEndianBytes(bigNum, 20);
|
|
23
|
+
const nonce = base64url.encode(Z);
|
|
24
|
+
if (nonce.length !== NONCE_LENGTH) {
|
|
25
|
+
throw new Error(`Length of nonce ${nonce} (${nonce.length}) is not equal to ${NONCE_LENGTH}`);
|
|
26
|
+
}
|
|
27
|
+
return nonce;
|
|
28
|
+
}
|
|
29
|
+
export {
|
|
30
|
+
NONCE_LENGTH,
|
|
31
|
+
generateNonce,
|
|
32
|
+
generateRandomness
|
|
33
|
+
};
|
|
34
|
+
//# sourceMappingURL=nonce.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/zklogin/nonce.ts"],
|
|
4
|
+
"sourcesContent": ["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { toHex } from '@mysten/bcs';\nimport { randomBytes } from '@noble/hashes/utils';\nimport { base64url } from 'jose';\n\nimport type { PublicKey } from '../cryptography/publickey.js';\nimport { poseidonHash } from './poseidon.js';\nimport { toPaddedBigEndianBytes } from './utils.js';\n\nexport const NONCE_LENGTH = 27;\n\nfunction toBigIntBE(bytes: Uint8Array) {\n\tconst hex = toHex(bytes);\n\tif (hex.length === 0) {\n\t\treturn BigInt(0);\n\t}\n\treturn BigInt(`0x${hex}`);\n}\n\nexport function generateRandomness() {\n\t// Once Node 20 enters LTS, we can just use crypto.getRandomValues(new Uint8Array(16)), but until then we use `randomBytes` to improve compatibility:\n\treturn String(toBigIntBE(randomBytes(16)));\n}\n\nexport function generateNonce(publicKey: PublicKey, maxEpoch: number, randomness: bigint | string) {\n\tconst publicKeyBytes = toBigIntBE(publicKey.toSuiBytes());\n\tconst eph_public_key_0 = publicKeyBytes / 2n ** 128n;\n\tconst eph_public_key_1 = publicKeyBytes % 2n ** 128n;\n\tconst bigNum = poseidonHash([eph_public_key_0, eph_public_key_1, maxEpoch, BigInt(randomness)]);\n\tconst Z = toPaddedBigEndianBytes(bigNum, 20);\n\tconst nonce = base64url.encode(Z);\n\tif (nonce.length !== NONCE_LENGTH) {\n\t\tthrow new Error(`Length of nonce ${nonce} (${nonce.length}) is not equal to ${NONCE_LENGTH}`);\n\t}\n\treturn nonce;\n}\n"],
|
|
5
|
+
"mappings": "AAGA,SAAS,aAAa;AACtB,SAAS,mBAAmB;AAC5B,SAAS,iBAAiB;AAG1B,SAAS,oBAAoB;AAC7B,SAAS,8BAA8B;AAEhC,MAAM,eAAe;AAE5B,SAAS,WAAW,OAAmB;AACtC,QAAM,MAAM,MAAM,KAAK;AACvB,MAAI,IAAI,WAAW,GAAG;AACrB,WAAO,OAAO,CAAC;AAAA,EAChB;AACA,SAAO,OAAO,KAAK,GAAG,EAAE;AACzB;AAEO,SAAS,qBAAqB;AAEpC,SAAO,OAAO,WAAW,YAAY,EAAE,CAAC,CAAC;AAC1C;AAEO,SAAS,cAAc,WAAsB,UAAkB,YAA6B;AAClG,QAAM,iBAAiB,WAAW,UAAU,WAAW,CAAC;AACxD,QAAM,mBAAmB,iBAAiB,MAAM;AAChD,QAAM,mBAAmB,iBAAiB,MAAM;AAChD,QAAM,SAAS,aAAa,CAAC,kBAAkB,kBAAkB,UAAU,OAAO,UAAU,CAAC,CAAC;AAC9F,QAAM,IAAI,uBAAuB,QAAQ,EAAE;AAC3C,QAAM,QAAQ,UAAU,OAAO,CAAC;AAChC,MAAI,MAAM,WAAW,cAAc;AAClC,UAAM,IAAI,MAAM,mBAAmB,KAAK,KAAK,MAAM,MAAM,qBAAqB,YAAY,EAAE;AAAA,EAC7F;AACA,SAAO;AACR;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import {
|
|
2
|
+
poseidon1,
|
|
3
|
+
poseidon2,
|
|
4
|
+
poseidon3,
|
|
5
|
+
poseidon4,
|
|
6
|
+
poseidon5,
|
|
7
|
+
poseidon6,
|
|
8
|
+
poseidon7,
|
|
9
|
+
poseidon8,
|
|
10
|
+
poseidon9,
|
|
11
|
+
poseidon10,
|
|
12
|
+
poseidon11,
|
|
13
|
+
poseidon12,
|
|
14
|
+
poseidon13,
|
|
15
|
+
poseidon14,
|
|
16
|
+
poseidon15,
|
|
17
|
+
poseidon16
|
|
18
|
+
} from "poseidon-lite";
|
|
19
|
+
const poseidonNumToHashFN = [
|
|
20
|
+
poseidon1,
|
|
21
|
+
poseidon2,
|
|
22
|
+
poseidon3,
|
|
23
|
+
poseidon4,
|
|
24
|
+
poseidon5,
|
|
25
|
+
poseidon6,
|
|
26
|
+
poseidon7,
|
|
27
|
+
poseidon8,
|
|
28
|
+
poseidon9,
|
|
29
|
+
poseidon10,
|
|
30
|
+
poseidon11,
|
|
31
|
+
poseidon12,
|
|
32
|
+
poseidon13,
|
|
33
|
+
poseidon14,
|
|
34
|
+
poseidon15,
|
|
35
|
+
poseidon16
|
|
36
|
+
];
|
|
37
|
+
const BN254_FIELD_SIZE = 21888242871839275222246405745257275088548364400416034343698204186575808495617n;
|
|
38
|
+
function poseidonHash(inputs) {
|
|
39
|
+
inputs.forEach((x) => {
|
|
40
|
+
const b = BigInt(x);
|
|
41
|
+
if (b < 0 || b >= BN254_FIELD_SIZE) {
|
|
42
|
+
throw new Error(`Element ${b} not in the BN254 field`);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
const hashFN = poseidonNumToHashFN[inputs.length - 1];
|
|
46
|
+
if (hashFN) {
|
|
47
|
+
return hashFN(inputs);
|
|
48
|
+
} else if (inputs.length <= 32) {
|
|
49
|
+
const hash1 = poseidonHash(inputs.slice(0, 16));
|
|
50
|
+
const hash2 = poseidonHash(inputs.slice(16));
|
|
51
|
+
return poseidonHash([hash1, hash2]);
|
|
52
|
+
} else {
|
|
53
|
+
throw new Error(`Yet to implement: Unable to hash a vector of length ${inputs.length}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
export {
|
|
57
|
+
BN254_FIELD_SIZE,
|
|
58
|
+
poseidonHash
|
|
59
|
+
};
|
|
60
|
+
//# sourceMappingURL=poseidon.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/zklogin/poseidon.ts"],
|
|
4
|
+
"sourcesContent": ["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport {\n\tposeidon1,\n\tposeidon2,\n\tposeidon3,\n\tposeidon4,\n\tposeidon5,\n\tposeidon6,\n\tposeidon7,\n\tposeidon8,\n\tposeidon9,\n\tposeidon10,\n\tposeidon11,\n\tposeidon12,\n\tposeidon13,\n\tposeidon14,\n\tposeidon15,\n\tposeidon16,\n} from 'poseidon-lite';\n\nconst poseidonNumToHashFN = [\n\tposeidon1,\n\tposeidon2,\n\tposeidon3,\n\tposeidon4,\n\tposeidon5,\n\tposeidon6,\n\tposeidon7,\n\tposeidon8,\n\tposeidon9,\n\tposeidon10,\n\tposeidon11,\n\tposeidon12,\n\tposeidon13,\n\tposeidon14,\n\tposeidon15,\n\tposeidon16,\n];\n\nexport const BN254_FIELD_SIZE =\n\t21888242871839275222246405745257275088548364400416034343698204186575808495617n;\n\nexport function poseidonHash(inputs: (number | bigint | string)[]): bigint {\n\tinputs.forEach((x) => {\n\t\tconst b = BigInt(x);\n\t\tif (b < 0 || b >= BN254_FIELD_SIZE) {\n\t\t\tthrow new Error(`Element ${b} not in the BN254 field`);\n\t\t}\n\t});\n\n\tconst hashFN = poseidonNumToHashFN[inputs.length - 1];\n\n\tif (hashFN) {\n\t\treturn hashFN(inputs);\n\t} else if (inputs.length <= 32) {\n\t\tconst hash1 = poseidonHash(inputs.slice(0, 16));\n\t\tconst hash2 = poseidonHash(inputs.slice(16));\n\t\treturn poseidonHash([hash1, hash2]);\n\t} else {\n\t\tthrow new Error(`Yet to implement: Unable to hash a vector of length ${inputs.length}`);\n\t}\n}\n"],
|
|
5
|
+
"mappings": "AAGA;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AAEP,MAAM,sBAAsB;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD;AAEO,MAAM,mBACZ;AAEM,SAAS,aAAa,QAA8C;AAC1E,SAAO,QAAQ,CAAC,MAAM;AACrB,UAAM,IAAI,OAAO,CAAC;AAClB,QAAI,IAAI,KAAK,KAAK,kBAAkB;AACnC,YAAM,IAAI,MAAM,WAAW,CAAC,yBAAyB;AAAA,IACtD;AAAA,EACD,CAAC;AAED,QAAM,SAAS,oBAAoB,OAAO,SAAS,CAAC;AAEpD,MAAI,QAAQ;AACX,WAAO,OAAO,MAAM;AAAA,EACrB,WAAW,OAAO,UAAU,IAAI;AAC/B,UAAM,QAAQ,aAAa,OAAO,MAAM,GAAG,EAAE,CAAC;AAC9C,UAAM,QAAQ,aAAa,OAAO,MAAM,EAAE,CAAC;AAC3C,WAAO,aAAa,CAAC,OAAO,KAAK,CAAC;AAAA,EACnC,OAAO;AACN,UAAM,IAAI,MAAM,uDAAuD,OAAO,MAAM,EAAE;AAAA,EACvF;AACD;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -17,6 +17,7 @@ export declare class ZkLoginPublicIdentifier extends PublicKey {
|
|
|
17
17
|
* Checks if two zkLogin public identifiers are equal
|
|
18
18
|
*/
|
|
19
19
|
equals(publicKey: ZkLoginPublicIdentifier): boolean;
|
|
20
|
+
toSuiAddress(): string;
|
|
20
21
|
/**
|
|
21
22
|
* Return the byte array representation of the zkLogin public identifier
|
|
22
23
|
*/
|
|
@@ -40,6 +41,7 @@ export declare class ZkLoginPublicIdentifier extends PublicKey {
|
|
|
40
41
|
}
|
|
41
42
|
export declare function toZkLoginPublicIdentifier(addressSeed: bigint, iss: string, options?: {
|
|
42
43
|
client?: SuiGraphQLClient;
|
|
44
|
+
legacyAddress?: boolean;
|
|
43
45
|
}): ZkLoginPublicIdentifier;
|
|
44
46
|
export declare function parseSerializedZkLoginSignature(signature: Uint8Array | string): {
|
|
45
47
|
serializedSignature: string;
|
|
@@ -5,15 +5,18 @@ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot
|
|
|
5
5
|
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
|
|
6
6
|
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
7
7
|
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
|
|
8
|
-
var _data, _client;
|
|
9
|
-
import { fromBase64, toBase64 } from "@mysten/bcs";
|
|
8
|
+
var _data, _client, _legacyAddress;
|
|
9
|
+
import { fromBase64, toBase64, toHex } from "@mysten/bcs";
|
|
10
|
+
import { blake2b } from "@noble/hashes/blake2b";
|
|
11
|
+
import { bytesToHex } from "@noble/hashes/utils";
|
|
10
12
|
import { PublicKey } from "../cryptography/publickey.js";
|
|
11
13
|
import { SIGNATURE_SCHEME_TO_FLAG } from "../cryptography/signature-scheme.js";
|
|
12
14
|
import { SuiGraphQLClient } from "../graphql/client.js";
|
|
13
15
|
import { graphql } from "../graphql/schemas/2024.4/index.js";
|
|
16
|
+
import { normalizeSuiAddress, SUI_ADDRESS_LENGTH } from "../utils/sui-types.js";
|
|
14
17
|
import { extractClaimValue } from "./jwt-utils.js";
|
|
15
18
|
import { parseZkLoginSignature } from "./signature.js";
|
|
16
|
-
import { toPaddedBigEndianBytes } from "./utils.js";
|
|
19
|
+
import { toBigEndianBytes, toPaddedBigEndianBytes } from "./utils.js";
|
|
17
20
|
const _ZkLoginPublicIdentifier = class _ZkLoginPublicIdentifier extends PublicKey {
|
|
18
21
|
/**
|
|
19
22
|
* Create a new ZkLoginPublicIdentifier object
|
|
@@ -23,6 +26,7 @@ const _ZkLoginPublicIdentifier = class _ZkLoginPublicIdentifier extends PublicKe
|
|
|
23
26
|
super();
|
|
24
27
|
__privateAdd(this, _data);
|
|
25
28
|
__privateAdd(this, _client);
|
|
29
|
+
__privateAdd(this, _legacyAddress);
|
|
26
30
|
__privateSet(this, _client, client);
|
|
27
31
|
if (typeof value === "string") {
|
|
28
32
|
__privateSet(this, _data, fromBase64(value));
|
|
@@ -31,6 +35,10 @@ const _ZkLoginPublicIdentifier = class _ZkLoginPublicIdentifier extends PublicKe
|
|
|
31
35
|
} else {
|
|
32
36
|
__privateSet(this, _data, Uint8Array.from(value));
|
|
33
37
|
}
|
|
38
|
+
__privateSet(this, _legacyAddress, __privateGet(this, _data).length !== __privateGet(this, _data)[0] + 1 + 32);
|
|
39
|
+
if (__privateGet(this, _legacyAddress)) {
|
|
40
|
+
__privateSet(this, _data, normalizeZkLoginPublicKeyBytes(__privateGet(this, _data)));
|
|
41
|
+
}
|
|
34
42
|
}
|
|
35
43
|
/**
|
|
36
44
|
* Checks if two zkLogin public identifiers are equal
|
|
@@ -38,6 +46,18 @@ const _ZkLoginPublicIdentifier = class _ZkLoginPublicIdentifier extends PublicKe
|
|
|
38
46
|
equals(publicKey) {
|
|
39
47
|
return super.equals(publicKey);
|
|
40
48
|
}
|
|
49
|
+
toSuiAddress() {
|
|
50
|
+
if (__privateGet(this, _legacyAddress)) {
|
|
51
|
+
const legacyBytes = normalizeZkLoginPublicKeyBytes(__privateGet(this, _data), true);
|
|
52
|
+
const addressBytes = new Uint8Array(legacyBytes.length + 1);
|
|
53
|
+
addressBytes[0] = this.flag();
|
|
54
|
+
addressBytes.set(legacyBytes, 1);
|
|
55
|
+
return normalizeSuiAddress(
|
|
56
|
+
bytesToHex(blake2b(addressBytes, { dkLen: 32 })).slice(0, SUI_ADDRESS_LENGTH * 2)
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
return super.toSuiAddress();
|
|
60
|
+
}
|
|
41
61
|
/**
|
|
42
62
|
* Return the byte array representation of the zkLogin public identifier
|
|
43
63
|
*/
|
|
@@ -87,9 +107,10 @@ const _ZkLoginPublicIdentifier = class _ZkLoginPublicIdentifier extends PublicKe
|
|
|
87
107
|
};
|
|
88
108
|
_data = new WeakMap();
|
|
89
109
|
_client = new WeakMap();
|
|
110
|
+
_legacyAddress = new WeakMap();
|
|
90
111
|
let ZkLoginPublicIdentifier = _ZkLoginPublicIdentifier;
|
|
91
112
|
function toZkLoginPublicIdentifier(addressSeed, iss, options) {
|
|
92
|
-
const addressSeedBytesBigEndian = toPaddedBigEndianBytes(addressSeed, 32);
|
|
113
|
+
const addressSeedBytesBigEndian = options?.legacyAddress ? toBigEndianBytes(addressSeed, 32) : toPaddedBigEndianBytes(addressSeed, 32);
|
|
93
114
|
const issBytes = new TextEncoder().encode(iss);
|
|
94
115
|
const tmp = new Uint8Array(1 + issBytes.length + addressSeedBytesBigEndian.length);
|
|
95
116
|
tmp.set([issBytes.length], 0);
|
|
@@ -115,6 +136,15 @@ const VerifyZkLoginSignatureQuery = graphql(`
|
|
|
115
136
|
}
|
|
116
137
|
}
|
|
117
138
|
`);
|
|
139
|
+
function normalizeZkLoginPublicKeyBytes(bytes, legacyAddress = false) {
|
|
140
|
+
const issByteLength = bytes[0] + 1;
|
|
141
|
+
const addressSeed = BigInt(`0x${toHex(bytes.slice(issByteLength))}`);
|
|
142
|
+
const seedBytes = legacyAddress ? toBigEndianBytes(addressSeed, 32) : toPaddedBigEndianBytes(addressSeed, 32);
|
|
143
|
+
const data = new Uint8Array(issByteLength + seedBytes.length);
|
|
144
|
+
data.set(bytes.slice(0, issByteLength), 0);
|
|
145
|
+
data.set(seedBytes, issByteLength);
|
|
146
|
+
return data;
|
|
147
|
+
}
|
|
118
148
|
async function graphqlVerifyZkLoginSignature({
|
|
119
149
|
address,
|
|
120
150
|
bytes,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/zklogin/publickey.ts"],
|
|
4
|
-
"sourcesContent": ["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { fromBase64, toBase64 } from '@mysten/bcs';\n\nimport { PublicKey } from '../cryptography/publickey.js';\nimport type { PublicKeyInitData } from '../cryptography/publickey.js';\nimport { SIGNATURE_SCHEME_TO_FLAG } from '../cryptography/signature-scheme.js';\nimport { SuiGraphQLClient } from '../graphql/client.js';\nimport { graphql } from '../graphql/schemas/2024.4/index.js';\nimport { extractClaimValue } from './jwt-utils.js';\nimport { parseZkLoginSignature } from './signature.js';\nimport { toPaddedBigEndianBytes } from './utils.js';\n\n/**\n * A zkLogin public identifier\n */\nexport class ZkLoginPublicIdentifier extends PublicKey {\n\t#data: Uint8Array;\n\t#client?: SuiGraphQLClient;\n\n\t/**\n\t * Create a new ZkLoginPublicIdentifier object\n\t * @param value zkLogin public identifier as buffer or base-64 encoded string\n\t */\n\tconstructor(value: PublicKeyInitData, { client }: { client?: SuiGraphQLClient } = {}) {\n\t\tsuper();\n\n\t\tthis.#client = client;\n\n\t\tif (typeof value === 'string') {\n\t\t\tthis.#data = fromBase64(value);\n\t\t} else if (value instanceof Uint8Array) {\n\t\t\tthis.#data = value;\n\t\t} else {\n\t\t\tthis.#data = Uint8Array.from(value);\n\t\t}\n\t}\n\n\t/**\n\t * Checks if two zkLogin public identifiers are equal\n\t */\n\toverride equals(publicKey: ZkLoginPublicIdentifier): boolean {\n\t\treturn super.equals(publicKey);\n\t}\n\n\t/**\n\t * Return the byte array representation of the zkLogin public identifier\n\t */\n\ttoRawBytes(): Uint8Array {\n\t\treturn this.#data;\n\t}\n\n\t/**\n\t * Return the Sui address associated with this ZkLogin public identifier\n\t */\n\tflag(): number {\n\t\treturn SIGNATURE_SCHEME_TO_FLAG['ZkLogin'];\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, _signature: Uint8Array | string): Promise<boolean> {\n\t\tthrow Error('does not support');\n\t}\n\n\t/**\n\t * Verifies that the signature is valid for for the provided PersonalMessage\n\t */\n\tverifyPersonalMessage(message: Uint8Array, signature: Uint8Array | string): Promise<boolean> {\n\t\tconst parsedSignature = parseSerializedZkLoginSignature(signature);\n\t\tconst address = new ZkLoginPublicIdentifier(parsedSignature.publicKey).toSuiAddress();\n\n\t\treturn graphqlVerifyZkLoginSignature({\n\t\t\taddress: address,\n\t\t\tbytes: toBase64(message),\n\t\t\tsignature: parsedSignature.serializedSignature,\n\t\t\tintentScope: 'PERSONAL_MESSAGE',\n\t\t\tclient: this.#client,\n\t\t});\n\t}\n\n\t/**\n\t * Verifies that the signature is valid for for the provided Transaction\n\t */\n\tverifyTransaction(transaction: Uint8Array, signature: Uint8Array | string): Promise<boolean> {\n\t\tconst parsedSignature = parseSerializedZkLoginSignature(signature);\n\t\tconst address = new ZkLoginPublicIdentifier(parsedSignature.publicKey).toSuiAddress();\n\t\treturn graphqlVerifyZkLoginSignature({\n\t\t\taddress: address,\n\t\t\tbytes: toBase64(transaction),\n\t\t\tsignature: parsedSignature.serializedSignature,\n\t\t\tintentScope: 'TRANSACTION_DATA',\n\t\t\tclient: this.#client,\n\t\t});\n\t}\n}\n\n// Derive the public identifier for zklogin based on address seed and iss.\nexport function toZkLoginPublicIdentifier(\n\taddressSeed: bigint,\n\tiss: string,\n\toptions?: { client?: SuiGraphQLClient },\n): ZkLoginPublicIdentifier {\n\t// Consists of iss_bytes_len || iss_bytes || padded_32_byte_address_seed.\n\tconst addressSeedBytesBigEndian = toPaddedBigEndianBytes(addressSeed, 32);\n\tconst issBytes = new TextEncoder().encode(iss);\n\tconst tmp = new Uint8Array(1 + issBytes.length + addressSeedBytesBigEndian.length);\n\ttmp.set([issBytes.length], 0);\n\ttmp.set(issBytes, 1);\n\ttmp.set(addressSeedBytesBigEndian, 1 + issBytes.length);\n\treturn new ZkLoginPublicIdentifier(tmp, options);\n}\n\nconst VerifyZkLoginSignatureQuery = graphql(`\n\tquery Zklogin(\n\t\t$bytes: Base64!\n\t\t$signature: Base64!\n\t\t$intentScope: ZkLoginIntentScope!\n\t\t$author: SuiAddress!\n\t) {\n\t\tverifyZkloginSignature(\n\t\t\tbytes: $bytes\n\t\t\tsignature: $signature\n\t\t\tintentScope: $intentScope\n\t\t\tauthor: $author\n\t\t) {\n\t\t\tsuccess\n\t\t\terrors\n\t\t}\n\t}\n`);\n\nasync function graphqlVerifyZkLoginSignature({\n\taddress,\n\tbytes,\n\tsignature,\n\tintentScope,\n\tclient = new SuiGraphQLClient({\n\t\turl: 'https://sui-mainnet.mystenlabs.com/graphql',\n\t}),\n}: {\n\taddress: string;\n\tbytes: string;\n\tsignature: string;\n\tintentScope: 'PERSONAL_MESSAGE' | 'TRANSACTION_DATA';\n\tclient?: SuiGraphQLClient;\n}) {\n\tconst resp = await client.query({\n\t\tquery: VerifyZkLoginSignatureQuery,\n\t\tvariables: {\n\t\t\tbytes,\n\t\t\tsignature,\n\t\t\tintentScope,\n\t\t\tauthor: address,\n\t\t},\n\t});\n\n\treturn (\n\t\tresp.data?.verifyZkloginSignature.success === true &&\n\t\tresp.data?.verifyZkloginSignature.errors.length === 0\n\t);\n}\n\nexport function parseSerializedZkLoginSignature(signature: Uint8Array | string) {\n\tconst bytes = typeof signature === 'string' ? fromBase64(signature) : signature;\n\n\tif (bytes[0] !== SIGNATURE_SCHEME_TO_FLAG.ZkLogin) {\n\t\tthrow new Error('Invalid signature scheme');\n\t}\n\n\tconst signatureBytes = bytes.slice(1);\n\tconst { inputs, maxEpoch, userSignature } = parseZkLoginSignature(signatureBytes);\n\tconst { issBase64Details, addressSeed } = inputs;\n\tconst iss = extractClaimValue<string>(issBase64Details, 'iss');\n\tconst publicIdentifer = toZkLoginPublicIdentifier(BigInt(addressSeed), iss);\n\treturn {\n\t\tserializedSignature: toBase64(bytes),\n\t\tsignatureScheme: 'ZkLogin' as const,\n\t\tzkLogin: {\n\t\t\tinputs,\n\t\t\tmaxEpoch,\n\t\t\tuserSignature,\n\t\t\tiss,\n\t\t\taddressSeed: BigInt(addressSeed),\n\t\t},\n\t\tsignature: bytes,\n\t\tpublicKey: publicIdentifer.toRawBytes(),\n\t};\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;AAAA;AAGA,SAAS,YAAY,
|
|
4
|
+
"sourcesContent": ["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { fromBase64, toBase64, toHex } from '@mysten/bcs';\nimport { blake2b } from '@noble/hashes/blake2b';\nimport { bytesToHex } from '@noble/hashes/utils';\n\nimport { PublicKey } from '../cryptography/publickey.js';\nimport type { PublicKeyInitData } from '../cryptography/publickey.js';\nimport { SIGNATURE_SCHEME_TO_FLAG } from '../cryptography/signature-scheme.js';\nimport { SuiGraphQLClient } from '../graphql/client.js';\nimport { graphql } from '../graphql/schemas/2024.4/index.js';\nimport { normalizeSuiAddress, SUI_ADDRESS_LENGTH } from '../utils/sui-types.js';\nimport { extractClaimValue } from './jwt-utils.js';\nimport { parseZkLoginSignature } from './signature.js';\nimport { toBigEndianBytes, toPaddedBigEndianBytes } from './utils.js';\n\n/**\n * A zkLogin public identifier\n */\nexport class ZkLoginPublicIdentifier extends PublicKey {\n\t#data: Uint8Array;\n\t#client?: SuiGraphQLClient;\n\t#legacyAddress: boolean;\n\n\t/**\n\t * Create a new ZkLoginPublicIdentifier object\n\t * @param value zkLogin public identifier as buffer or base-64 encoded string\n\t */\n\tconstructor(value: PublicKeyInitData, { client }: { client?: SuiGraphQLClient } = {}) {\n\t\tsuper();\n\n\t\tthis.#client = client;\n\n\t\tif (typeof value === 'string') {\n\t\t\tthis.#data = fromBase64(value);\n\t\t} else if (value instanceof Uint8Array) {\n\t\t\tthis.#data = value;\n\t\t} else {\n\t\t\tthis.#data = Uint8Array.from(value);\n\t\t}\n\t\tthis.#legacyAddress = this.#data.length !== this.#data[0] + 1 + 32;\n\n\t\tif (this.#legacyAddress) {\n\t\t\tthis.#data = normalizeZkLoginPublicKeyBytes(this.#data);\n\t\t}\n\t}\n\n\t/**\n\t * Checks if two zkLogin public identifiers are equal\n\t */\n\toverride equals(publicKey: ZkLoginPublicIdentifier): boolean {\n\t\treturn super.equals(publicKey);\n\t}\n\n\toverride toSuiAddress(): string {\n\t\tif (this.#legacyAddress) {\n\t\t\tconst legacyBytes = normalizeZkLoginPublicKeyBytes(this.#data, true);\n\t\t\tconst addressBytes = new Uint8Array(legacyBytes.length + 1);\n\t\t\taddressBytes[0] = this.flag();\n\t\t\taddressBytes.set(legacyBytes, 1);\n\t\t\treturn normalizeSuiAddress(\n\t\t\t\tbytesToHex(blake2b(addressBytes, { dkLen: 32 })).slice(0, SUI_ADDRESS_LENGTH * 2),\n\t\t\t);\n\t\t}\n\n\t\treturn super.toSuiAddress();\n\t}\n\n\t/**\n\t * Return the byte array representation of the zkLogin public identifier\n\t */\n\ttoRawBytes(): Uint8Array {\n\t\treturn this.#data;\n\t}\n\n\t/**\n\t * Return the Sui address associated with this ZkLogin public identifier\n\t */\n\tflag(): number {\n\t\treturn SIGNATURE_SCHEME_TO_FLAG['ZkLogin'];\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, _signature: Uint8Array | string): Promise<boolean> {\n\t\tthrow Error('does not support');\n\t}\n\n\t/**\n\t * Verifies that the signature is valid for for the provided PersonalMessage\n\t */\n\tverifyPersonalMessage(message: Uint8Array, signature: Uint8Array | string): Promise<boolean> {\n\t\tconst parsedSignature = parseSerializedZkLoginSignature(signature);\n\t\tconst address = new ZkLoginPublicIdentifier(parsedSignature.publicKey).toSuiAddress();\n\n\t\treturn graphqlVerifyZkLoginSignature({\n\t\t\taddress: address,\n\t\t\tbytes: toBase64(message),\n\t\t\tsignature: parsedSignature.serializedSignature,\n\t\t\tintentScope: 'PERSONAL_MESSAGE',\n\t\t\tclient: this.#client,\n\t\t});\n\t}\n\n\t/**\n\t * Verifies that the signature is valid for for the provided Transaction\n\t */\n\tverifyTransaction(transaction: Uint8Array, signature: Uint8Array | string): Promise<boolean> {\n\t\tconst parsedSignature = parseSerializedZkLoginSignature(signature);\n\t\tconst address = new ZkLoginPublicIdentifier(parsedSignature.publicKey).toSuiAddress();\n\t\treturn graphqlVerifyZkLoginSignature({\n\t\t\taddress: address,\n\t\t\tbytes: toBase64(transaction),\n\t\t\tsignature: parsedSignature.serializedSignature,\n\t\t\tintentScope: 'TRANSACTION_DATA',\n\t\t\tclient: this.#client,\n\t\t});\n\t}\n}\n\n// Derive the public identifier for zklogin based on address seed and iss.\nexport function toZkLoginPublicIdentifier(\n\taddressSeed: bigint,\n\tiss: string,\n\toptions?: { client?: SuiGraphQLClient; legacyAddress?: boolean },\n): ZkLoginPublicIdentifier {\n\t// Consists of iss_bytes_len || iss_bytes || padded_32_byte_address_seed.\n\tconst addressSeedBytesBigEndian = options?.legacyAddress\n\t\t? toBigEndianBytes(addressSeed, 32)\n\t\t: toPaddedBigEndianBytes(addressSeed, 32);\n\n\tconst issBytes = new TextEncoder().encode(iss);\n\tconst tmp = new Uint8Array(1 + issBytes.length + addressSeedBytesBigEndian.length);\n\ttmp.set([issBytes.length], 0);\n\ttmp.set(issBytes, 1);\n\ttmp.set(addressSeedBytesBigEndian, 1 + issBytes.length);\n\treturn new ZkLoginPublicIdentifier(tmp, options);\n}\n\nconst VerifyZkLoginSignatureQuery = graphql(`\n\tquery Zklogin(\n\t\t$bytes: Base64!\n\t\t$signature: Base64!\n\t\t$intentScope: ZkLoginIntentScope!\n\t\t$author: SuiAddress!\n\t) {\n\t\tverifyZkloginSignature(\n\t\t\tbytes: $bytes\n\t\t\tsignature: $signature\n\t\t\tintentScope: $intentScope\n\t\t\tauthor: $author\n\t\t) {\n\t\t\tsuccess\n\t\t\terrors\n\t\t}\n\t}\n`);\n\nfunction normalizeZkLoginPublicKeyBytes(bytes: Uint8Array, legacyAddress = false) {\n\tconst issByteLength = bytes[0] + 1;\n\tconst addressSeed = BigInt(`0x${toHex(bytes.slice(issByteLength))}`);\n\tconst seedBytes = legacyAddress\n\t\t? toBigEndianBytes(addressSeed, 32)\n\t\t: toPaddedBigEndianBytes(addressSeed, 32);\n\tconst data = new Uint8Array(issByteLength + seedBytes.length);\n\tdata.set(bytes.slice(0, issByteLength), 0);\n\tdata.set(seedBytes, issByteLength);\n\treturn data;\n}\n\nasync function graphqlVerifyZkLoginSignature({\n\taddress,\n\tbytes,\n\tsignature,\n\tintentScope,\n\tclient = new SuiGraphQLClient({\n\t\turl: 'https://sui-mainnet.mystenlabs.com/graphql',\n\t}),\n}: {\n\taddress: string;\n\tbytes: string;\n\tsignature: string;\n\tintentScope: 'PERSONAL_MESSAGE' | 'TRANSACTION_DATA';\n\tclient?: SuiGraphQLClient;\n}) {\n\tconst resp = await client.query({\n\t\tquery: VerifyZkLoginSignatureQuery,\n\t\tvariables: {\n\t\t\tbytes,\n\t\t\tsignature,\n\t\t\tintentScope,\n\t\t\tauthor: address,\n\t\t},\n\t});\n\n\treturn (\n\t\tresp.data?.verifyZkloginSignature.success === true &&\n\t\tresp.data?.verifyZkloginSignature.errors.length === 0\n\t);\n}\n\nexport function parseSerializedZkLoginSignature(signature: Uint8Array | string) {\n\tconst bytes = typeof signature === 'string' ? fromBase64(signature) : signature;\n\n\tif (bytes[0] !== SIGNATURE_SCHEME_TO_FLAG.ZkLogin) {\n\t\tthrow new Error('Invalid signature scheme');\n\t}\n\n\tconst signatureBytes = bytes.slice(1);\n\tconst { inputs, maxEpoch, userSignature } = parseZkLoginSignature(signatureBytes);\n\tconst { issBase64Details, addressSeed } = inputs;\n\tconst iss = extractClaimValue<string>(issBase64Details, 'iss');\n\tconst publicIdentifer = toZkLoginPublicIdentifier(BigInt(addressSeed), iss);\n\treturn {\n\t\tserializedSignature: toBase64(bytes),\n\t\tsignatureScheme: 'ZkLogin' as const,\n\t\tzkLogin: {\n\t\t\tinputs,\n\t\t\tmaxEpoch,\n\t\t\tuserSignature,\n\t\t\tiss,\n\t\t\taddressSeed: BigInt(addressSeed),\n\t\t},\n\t\tsignature: bytes,\n\t\tpublicKey: publicIdentifer.toRawBytes(),\n\t};\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,2 +1,15 @@
|
|
|
1
|
+
import type { PublicKey } from '../cryptography/publickey.js';
|
|
1
2
|
export declare function toPaddedBigEndianBytes(num: bigint, width: number): Uint8Array;
|
|
2
3
|
export declare function toBigEndianBytes(num: bigint, width: number): Uint8Array;
|
|
4
|
+
export declare function getExtendedEphemeralPublicKey(publicKey: PublicKey): string;
|
|
5
|
+
/**
|
|
6
|
+
* Splits an array into chunks of size chunk_size. If the array is not evenly
|
|
7
|
+
* divisible by chunk_size, the first chunk will be smaller than chunk_size.
|
|
8
|
+
*
|
|
9
|
+
* E.g., arrayChunk([1, 2, 3, 4, 5], 2) => [[1], [2, 3], [4, 5]]
|
|
10
|
+
*
|
|
11
|
+
* Note: Can be made more efficient by avoiding the reverse() calls.
|
|
12
|
+
*/
|
|
13
|
+
export declare function chunkArray<T>(array: T[], chunk_size: number): T[][];
|
|
14
|
+
export declare function hashASCIIStrToField(str: string, maxSize: number): bigint;
|
|
15
|
+
export declare function genAddressSeed(salt: string | bigint, name: string, value: string, aud: string, max_name_length?: number, max_value_length?: number, max_aud_length?: number): bigint;
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import { hexToBytes } from "@noble/hashes/utils";
|
|
2
|
+
import { poseidonHash } from "./poseidon.js";
|
|
3
|
+
const MAX_KEY_CLAIM_NAME_LENGTH = 32;
|
|
4
|
+
const MAX_KEY_CLAIM_VALUE_LENGTH = 115;
|
|
5
|
+
const MAX_AUD_VALUE_LENGTH = 145;
|
|
6
|
+
const PACK_WIDTH = 248;
|
|
2
7
|
function findFirstNonZeroIndex(bytes) {
|
|
3
8
|
for (let i = 0; i < bytes.length; i++) {
|
|
4
9
|
if (bytes[i] !== 0) {
|
|
@@ -19,7 +24,46 @@ function toBigEndianBytes(num, width) {
|
|
|
19
24
|
}
|
|
20
25
|
return bytes.slice(firstNonZeroIndex);
|
|
21
26
|
}
|
|
27
|
+
function getExtendedEphemeralPublicKey(publicKey) {
|
|
28
|
+
return publicKey.toSuiPublicKey();
|
|
29
|
+
}
|
|
30
|
+
function chunkArray(array, chunk_size) {
|
|
31
|
+
const chunks = Array(Math.ceil(array.length / chunk_size));
|
|
32
|
+
const revArray = array.reverse();
|
|
33
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
34
|
+
chunks[i] = revArray.slice(i * chunk_size, (i + 1) * chunk_size).reverse();
|
|
35
|
+
}
|
|
36
|
+
return chunks.reverse();
|
|
37
|
+
}
|
|
38
|
+
function bytesBEToBigInt(bytes) {
|
|
39
|
+
const hex = bytes.map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
40
|
+
if (hex.length === 0) {
|
|
41
|
+
return BigInt(0);
|
|
42
|
+
}
|
|
43
|
+
return BigInt("0x" + hex);
|
|
44
|
+
}
|
|
45
|
+
function hashASCIIStrToField(str, maxSize) {
|
|
46
|
+
if (str.length > maxSize) {
|
|
47
|
+
throw new Error(`String ${str} is longer than ${maxSize} chars`);
|
|
48
|
+
}
|
|
49
|
+
const strPadded = str.padEnd(maxSize, String.fromCharCode(0)).split("").map((c) => c.charCodeAt(0));
|
|
50
|
+
const chunkSize = PACK_WIDTH / 8;
|
|
51
|
+
const packed = chunkArray(strPadded, chunkSize).map((chunk) => bytesBEToBigInt(chunk));
|
|
52
|
+
return poseidonHash(packed);
|
|
53
|
+
}
|
|
54
|
+
function genAddressSeed(salt, name, value, aud, max_name_length = MAX_KEY_CLAIM_NAME_LENGTH, max_value_length = MAX_KEY_CLAIM_VALUE_LENGTH, max_aud_length = MAX_AUD_VALUE_LENGTH) {
|
|
55
|
+
return poseidonHash([
|
|
56
|
+
hashASCIIStrToField(name, max_name_length),
|
|
57
|
+
hashASCIIStrToField(value, max_value_length),
|
|
58
|
+
hashASCIIStrToField(aud, max_aud_length),
|
|
59
|
+
poseidonHash([BigInt(salt)])
|
|
60
|
+
]);
|
|
61
|
+
}
|
|
22
62
|
export {
|
|
63
|
+
chunkArray,
|
|
64
|
+
genAddressSeed,
|
|
65
|
+
getExtendedEphemeralPublicKey,
|
|
66
|
+
hashASCIIStrToField,
|
|
23
67
|
toBigEndianBytes,
|
|
24
68
|
toPaddedBigEndianBytes
|
|
25
69
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/zklogin/utils.ts"],
|
|
4
|
-
"sourcesContent": ["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { hexToBytes } from '@noble/hashes/utils';\n\nfunction findFirstNonZeroIndex(bytes: Uint8Array) {\n\tfor (let i = 0; i < bytes.length; i++) {\n\t\tif (bytes[i] !== 0) {\n\t\t\treturn i;\n\t\t}\n\t}\n\n\treturn -1;\n}\n\n// Derive bytearray from num where the bytearray is padded to the left with 0s to the specified width.\nexport function toPaddedBigEndianBytes(num: bigint, width: number): Uint8Array {\n\tconst hex = num.toString(16);\n\treturn hexToBytes(hex.padStart(width * 2, '0').slice(-width * 2));\n}\n\n// Derive bytearray from num where the bytearray is not padded with 0.\nexport function toBigEndianBytes(num: bigint, width: number): Uint8Array {\n\tconst bytes = toPaddedBigEndianBytes(num, width);\n\n\tconst firstNonZeroIndex = findFirstNonZeroIndex(bytes);\n\n\tif (firstNonZeroIndex === -1) {\n\t\treturn new Uint8Array([0]);\n\t}\n\n\treturn bytes.slice(firstNonZeroIndex);\n}\n"],
|
|
5
|
-
"mappings": "AAGA,SAAS,kBAAkB;
|
|
4
|
+
"sourcesContent": ["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { hexToBytes } from '@noble/hashes/utils';\n\nimport type { PublicKey } from '../cryptography/publickey.js';\nimport { poseidonHash } from './poseidon.js';\n\nconst MAX_KEY_CLAIM_NAME_LENGTH = 32;\nconst MAX_KEY_CLAIM_VALUE_LENGTH = 115;\nconst MAX_AUD_VALUE_LENGTH = 145;\nconst PACK_WIDTH = 248;\n\nfunction findFirstNonZeroIndex(bytes: Uint8Array) {\n\tfor (let i = 0; i < bytes.length; i++) {\n\t\tif (bytes[i] !== 0) {\n\t\t\treturn i;\n\t\t}\n\t}\n\n\treturn -1;\n}\n\n// Derive bytearray from num where the bytearray is padded to the left with 0s to the specified width.\nexport function toPaddedBigEndianBytes(num: bigint, width: number): Uint8Array {\n\tconst hex = num.toString(16);\n\treturn hexToBytes(hex.padStart(width * 2, '0').slice(-width * 2));\n}\n\n// Derive bytearray from num where the bytearray is not padded with 0.\nexport function toBigEndianBytes(num: bigint, width: number): Uint8Array {\n\tconst bytes = toPaddedBigEndianBytes(num, width);\n\n\tconst firstNonZeroIndex = findFirstNonZeroIndex(bytes);\n\n\tif (firstNonZeroIndex === -1) {\n\t\treturn new Uint8Array([0]);\n\t}\n\n\treturn bytes.slice(firstNonZeroIndex);\n}\n\nexport function getExtendedEphemeralPublicKey(publicKey: PublicKey) {\n\treturn publicKey.toSuiPublicKey();\n}\n\n/**\n * Splits an array into chunks of size chunk_size. If the array is not evenly\n * divisible by chunk_size, the first chunk will be smaller than chunk_size.\n *\n * E.g., arrayChunk([1, 2, 3, 4, 5], 2) => [[1], [2, 3], [4, 5]]\n *\n * Note: Can be made more efficient by avoiding the reverse() calls.\n */\nexport function chunkArray<T>(array: T[], chunk_size: number): T[][] {\n\tconst chunks = Array(Math.ceil(array.length / chunk_size));\n\tconst revArray = array.reverse();\n\tfor (let i = 0; i < chunks.length; i++) {\n\t\tchunks[i] = revArray.slice(i * chunk_size, (i + 1) * chunk_size).reverse();\n\t}\n\treturn chunks.reverse();\n}\n\nfunction bytesBEToBigInt(bytes: number[]): bigint {\n\tconst hex = bytes.map((b) => b.toString(16).padStart(2, '0')).join('');\n\tif (hex.length === 0) {\n\t\treturn BigInt(0);\n\t}\n\treturn BigInt('0x' + hex);\n}\n\n// hashes an ASCII string to a field element\nexport function hashASCIIStrToField(str: string, maxSize: number) {\n\tif (str.length > maxSize) {\n\t\tthrow new Error(`String ${str} is longer than ${maxSize} chars`);\n\t}\n\n\t// Note: Padding with zeroes is safe because we are only using this function to map human-readable sequence of bytes.\n\t// So the ASCII values of those characters will never be zero (null character).\n\tconst strPadded = str\n\t\t.padEnd(maxSize, String.fromCharCode(0))\n\t\t.split('')\n\t\t.map((c) => c.charCodeAt(0));\n\n\tconst chunkSize = PACK_WIDTH / 8;\n\tconst packed = chunkArray(strPadded, chunkSize).map((chunk) => bytesBEToBigInt(chunk));\n\treturn poseidonHash(packed);\n}\n\nexport function genAddressSeed(\n\tsalt: string | bigint,\n\tname: string,\n\tvalue: string,\n\taud: string,\n\tmax_name_length = MAX_KEY_CLAIM_NAME_LENGTH,\n\tmax_value_length = MAX_KEY_CLAIM_VALUE_LENGTH,\n\tmax_aud_length = MAX_AUD_VALUE_LENGTH,\n): bigint {\n\treturn poseidonHash([\n\t\thashASCIIStrToField(name, max_name_length),\n\t\thashASCIIStrToField(value, max_value_length),\n\t\thashASCIIStrToField(aud, max_aud_length),\n\t\tposeidonHash([BigInt(salt)]),\n\t]);\n}\n"],
|
|
5
|
+
"mappings": "AAGA,SAAS,kBAAkB;AAG3B,SAAS,oBAAoB;AAE7B,MAAM,4BAA4B;AAClC,MAAM,6BAA6B;AACnC,MAAM,uBAAuB;AAC7B,MAAM,aAAa;AAEnB,SAAS,sBAAsB,OAAmB;AACjD,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACtC,QAAI,MAAM,CAAC,MAAM,GAAG;AACnB,aAAO;AAAA,IACR;AAAA,EACD;AAEA,SAAO;AACR;AAGO,SAAS,uBAAuB,KAAa,OAA2B;AAC9E,QAAM,MAAM,IAAI,SAAS,EAAE;AAC3B,SAAO,WAAW,IAAI,SAAS,QAAQ,GAAG,GAAG,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;AACjE;AAGO,SAAS,iBAAiB,KAAa,OAA2B;AACxE,QAAM,QAAQ,uBAAuB,KAAK,KAAK;AAE/C,QAAM,oBAAoB,sBAAsB,KAAK;AAErD,MAAI,sBAAsB,IAAI;AAC7B,WAAO,IAAI,WAAW,CAAC,CAAC,CAAC;AAAA,EAC1B;AAEA,SAAO,MAAM,MAAM,iBAAiB;AACrC;AAEO,SAAS,8BAA8B,WAAsB;AACnE,SAAO,UAAU,eAAe;AACjC;AAUO,SAAS,WAAc,OAAY,YAA2B;AACpE,QAAM,SAAS,MAAM,KAAK,KAAK,MAAM,SAAS,UAAU,CAAC;AACzD,QAAM,WAAW,MAAM,QAAQ;AAC/B,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACvC,WAAO,CAAC,IAAI,SAAS,MAAM,IAAI,aAAa,IAAI,KAAK,UAAU,EAAE,QAAQ;AAAA,EAC1E;AACA,SAAO,OAAO,QAAQ;AACvB;AAEA,SAAS,gBAAgB,OAAyB;AACjD,QAAM,MAAM,MAAM,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EAAE,KAAK,EAAE;AACrE,MAAI,IAAI,WAAW,GAAG;AACrB,WAAO,OAAO,CAAC;AAAA,EAChB;AACA,SAAO,OAAO,OAAO,GAAG;AACzB;AAGO,SAAS,oBAAoB,KAAa,SAAiB;AACjE,MAAI,IAAI,SAAS,SAAS;AACzB,UAAM,IAAI,MAAM,UAAU,GAAG,mBAAmB,OAAO,QAAQ;AAAA,EAChE;AAIA,QAAM,YAAY,IAChB,OAAO,SAAS,OAAO,aAAa,CAAC,CAAC,EACtC,MAAM,EAAE,EACR,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;AAE5B,QAAM,YAAY,aAAa;AAC/B,QAAM,SAAS,WAAW,WAAW,SAAS,EAAE,IAAI,CAAC,UAAU,gBAAgB,KAAK,CAAC;AACrF,SAAO,aAAa,MAAM;AAC3B;AAEO,SAAS,eACf,MACA,MACA,OACA,KACA,kBAAkB,2BAClB,mBAAmB,4BACnB,iBAAiB,sBACR;AACT,SAAO,aAAa;AAAA,IACnB,oBAAoB,MAAM,eAAe;AAAA,IACzC,oBAAoB,OAAO,gBAAgB;AAAA,IAC3C,oBAAoB,KAAK,cAAc;AAAA,IACvC,aAAa,CAAC,OAAO,IAAI,CAAC,CAAC;AAAA,EAC5B,CAAC;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|