@aztec/key-store 0.0.1-commit.fce3e4f → 0.0.1-commit.ff7989d6c
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/dest/key_store.d.ts +13 -3
- package/dest/key_store.d.ts.map +1 -1
- package/dest/key_store.js +54 -25
- package/package.json +8 -8
- package/src/key_store.ts +63 -27
package/dest/key_store.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { Fr
|
|
1
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
2
|
+
import { GrumpkinScalar } from '@aztec/foundation/curves/grumpkin';
|
|
2
3
|
import { type Bufferable } from '@aztec/foundation/serialize';
|
|
3
4
|
import type { AztecAsyncKVStore } from '@aztec/kv-store';
|
|
4
5
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
@@ -10,7 +11,7 @@ import { type KeyPrefix, type PublicKey } from '@aztec/stdlib/keys';
|
|
|
10
11
|
*/
|
|
11
12
|
export declare class KeyStore {
|
|
12
13
|
#private;
|
|
13
|
-
static readonly SCHEMA_VERSION
|
|
14
|
+
static readonly SCHEMA_VERSION = 1;
|
|
14
15
|
constructor(database: AztecAsyncKVStore);
|
|
15
16
|
/**
|
|
16
17
|
* Creates a new account from a randomly generated secret key.
|
|
@@ -29,6 +30,8 @@ export declare class KeyStore {
|
|
|
29
30
|
* @returns A Promise that resolves to an array of account addresses.
|
|
30
31
|
*/
|
|
31
32
|
getAccounts(): Promise<AztecAddress[]>;
|
|
33
|
+
/** Checks whether an account is registered in the key store. */
|
|
34
|
+
hasAccount(account: AztecAddress): Promise<boolean>;
|
|
32
35
|
/**
|
|
33
36
|
* Gets the key validation request for a given master public key hash and contract address.
|
|
34
37
|
* @throws If the account corresponding to the master public key hash does not exist in the key store.
|
|
@@ -88,6 +91,13 @@ export declare class KeyStore {
|
|
|
88
91
|
* @dev Used when feeding the sk_m to the kernel circuit for keys verification.
|
|
89
92
|
*/
|
|
90
93
|
getMasterSecretKey(pkM: PublicKey): Promise<GrumpkinScalar>;
|
|
94
|
+
/**
|
|
95
|
+
* Checks whether a given account has a key matching the provided master public key hash.
|
|
96
|
+
* @param account - The account address to check.
|
|
97
|
+
* @param pkMHash - The master public key hash to look for.
|
|
98
|
+
* @returns True if the account has a key with the given hash.
|
|
99
|
+
*/
|
|
100
|
+
accountHasKey(account: AztecAddress, pkMHash: Fr): Promise<boolean>;
|
|
91
101
|
/**
|
|
92
102
|
* Gets the key prefix and account address for a given value.
|
|
93
103
|
* @returns A tuple containing the key prefix and account address.
|
|
@@ -96,4 +106,4 @@ export declare class KeyStore {
|
|
|
96
106
|
*/
|
|
97
107
|
getKeyPrefixAndAccount(value: Bufferable): Promise<[KeyPrefix, AztecAddress]>;
|
|
98
108
|
}
|
|
99
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
109
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoia2V5X3N0b3JlLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMva2V5X3N0b3JlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUVBLE9BQU8sRUFBRSxFQUFFLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUNwRCxPQUFPLEVBQUUsY0FBYyxFQUFTLE1BQU0sbUNBQW1DLENBQUM7QUFFMUUsT0FBTyxFQUFFLEtBQUssVUFBVSxFQUFxQixNQUFNLDZCQUE2QixDQUFDO0FBQ2pGLE9BQU8sS0FBSyxFQUFFLGlCQUFpQixFQUFpQixNQUFNLGlCQUFpQixDQUFDO0FBQ3hFLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUMzRCxPQUFPLEVBQUUsZUFBZSxFQUFFLEtBQUssY0FBYyxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDOUUsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDNUQsT0FBTyxFQUVMLEtBQUssU0FBUyxFQUNkLEtBQUssU0FBUyxFQUlmLE1BQU0sb0JBQW9CLENBQUM7QUFPNUI7O0dBRUc7QUFDSCxxQkFBYSxRQUFROztJQUNuQixnQkFBdUIsY0FBYyxLQUFLO0lBSTFDLFlBQVksUUFBUSxFQUFFLGlCQUFpQixFQUd0QztJQUVEOzs7T0FHRztJQUNJLGFBQWEsSUFBSSxPQUFPLENBQUMsZUFBZSxDQUFDLENBSS9DO0lBRUQ7Ozs7O09BS0c7SUFDVSxVQUFVLENBQUMsRUFBRSxFQUFFLEVBQUUsRUFBRSxjQUFjLEVBQUUsY0FBYyxHQUFHLE9BQU8sQ0FBQyxlQUFlLENBQUMsQ0F3Q3hGO0lBRUQ7OztPQUdHO0lBQ1UsV0FBVyxJQUFJLE9BQU8sQ0FBQyxZQUFZLEVBQUUsQ0FBQyxDQUtsRDtJQUVELGdFQUFnRTtJQUNuRCxVQUFVLENBQUMsT0FBTyxFQUFFLFlBQVksR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDLENBRS9EO0lBRUQ7Ozs7OztPQU1HO0lBQ1UsdUJBQXVCLENBQUMsT0FBTyxFQUFFLEVBQUUsRUFBRSxlQUFlLEVBQUUsWUFBWSxHQUFHLE9BQU8sQ0FBQyxvQkFBb0IsQ0FBQyxDQXNDOUc7SUFFRDs7Ozs7T0FLRztJQUNVLDJCQUEyQixDQUFDLE9BQU8sRUFBRSxZQUFZLEdBQUcsT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQVFsRjtJQUVEOzs7OztPQUtHO0lBQ1UsaUNBQWlDLENBQUMsT0FBTyxFQUFFLFlBQVksR0FBRyxPQUFPLENBQUMsU0FBUyxDQUFDLENBUXhGO0lBRUQ7Ozs7O09BS0c7SUFDVSxpQ0FBaUMsQ0FBQyxPQUFPLEVBQUUsWUFBWSxHQUFHLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FReEY7SUFFRDs7Ozs7T0FLRztJQUNVLHlCQUF5QixDQUFDLE9BQU8sRUFBRSxZQUFZLEdBQUcsT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQVFoRjtJQUVEOzs7OztPQUtHO0lBQ1UsaUNBQWlDLENBQUMsT0FBTyxFQUFFLFlBQVksR0FBRyxPQUFPLENBQUMsY0FBYyxDQUFDLENBUTdGO0lBRUQ7Ozs7OztPQU1HO0lBQ1UsOEJBQThCLENBQUMsT0FBTyxFQUFFLFlBQVksRUFBRSxHQUFHLEVBQUUsWUFBWSxHQUFHLE9BQU8sQ0FBQyxFQUFFLENBQUMsQ0Fhakc7SUFFRDs7Ozs7O09BTUc7SUFDVSxrQkFBa0IsQ0FBQyxHQUFHLEVBQUUsU0FBUyxHQUFHLE9BQU8sQ0FBQyxjQUFjLENBQUMsQ0FrQnZFO0lBRUQ7Ozs7O09BS0c7SUFDVSxhQUFhLENBQUMsT0FBTyxFQUFFLFlBQVksRUFBRSxPQUFPLEVBQUUsRUFBRSxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FTL0U7SUFFRDs7Ozs7T0FLRztJQUNVLHNCQUFzQixDQUFDLEtBQUssRUFBRSxVQUFVLEdBQUcsT0FBTyxDQUFDLENBQUMsU0FBUyxFQUFFLFlBQVksQ0FBQyxDQUFDLENBY3pGO0NBQ0YifQ==
|
package/dest/key_store.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"key_store.d.ts","sourceRoot":"","sources":["../src/key_store.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,EAAE,EAAE,cAAc,EAAS,MAAM,
|
|
1
|
+
{"version":3,"file":"key_store.d.ts","sourceRoot":"","sources":["../src/key_store.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AACpD,OAAO,EAAE,cAAc,EAAS,MAAM,mCAAmC,CAAC;AAE1E,OAAO,EAAE,KAAK,UAAU,EAAqB,MAAM,6BAA6B,CAAC;AACjF,OAAO,KAAK,EAAE,iBAAiB,EAAiB,MAAM,iBAAiB,CAAC;AACxE,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,KAAK,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAEL,KAAK,SAAS,EACd,KAAK,SAAS,EAIf,MAAM,oBAAoB,CAAC;AAO5B;;GAEG;AACH,qBAAa,QAAQ;;IACnB,gBAAuB,cAAc,KAAK;IAI1C,YAAY,QAAQ,EAAE,iBAAiB,EAGtC;IAED;;;OAGG;IACI,aAAa,IAAI,OAAO,CAAC,eAAe,CAAC,CAI/C;IAED;;;;;OAKG;IACU,UAAU,CAAC,EAAE,EAAE,EAAE,EAAE,cAAc,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC,CAwCxF;IAED;;;OAGG;IACU,WAAW,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC,CAKlD;IAED,gEAAgE;IACnD,UAAU,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,CAE/D;IAED;;;;;;OAMG;IACU,uBAAuB,CAAC,OAAO,EAAE,EAAE,EAAE,eAAe,EAAE,YAAY,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAsC9G;IAED;;;;;OAKG;IACU,2BAA2B,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,SAAS,CAAC,CAQlF;IAED;;;;;OAKG;IACU,iCAAiC,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,SAAS,CAAC,CAQxF;IAED;;;;;OAKG;IACU,iCAAiC,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,SAAS,CAAC,CAQxF;IAED;;;;;OAKG;IACU,yBAAyB,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,SAAS,CAAC,CAQhF;IAED;;;;;OAKG;IACU,iCAAiC,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,cAAc,CAAC,CAQ7F;IAED;;;;;;OAMG;IACU,8BAA8B,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,EAAE,CAAC,CAajG;IAED;;;;;;OAMG;IACU,kBAAkB,CAAC,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,cAAc,CAAC,CAkBvE;IAED;;;;;OAKG;IACU,aAAa,CAAC,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAS/E;IAED;;;;;OAKG;IACU,sBAAsB,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC,CAczF;CACF"}
|
package/dest/key_store.js
CHANGED
|
@@ -1,18 +1,24 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { poseidon2HashWithSeparator } from '@aztec/foundation/crypto';
|
|
3
|
-
import { Fr
|
|
1
|
+
import { DomainSeparator } from '@aztec/constants';
|
|
2
|
+
import { poseidon2HashWithSeparator } from '@aztec/foundation/crypto/poseidon';
|
|
3
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
4
|
+
import { GrumpkinScalar, Point } from '@aztec/foundation/curves/grumpkin';
|
|
4
5
|
import { toArray } from '@aztec/foundation/iterable';
|
|
5
6
|
import { serializeToBuffer } from '@aztec/foundation/serialize';
|
|
6
7
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
7
8
|
import { CompleteAddress } from '@aztec/stdlib/contract';
|
|
8
9
|
import { KeyValidationRequest } from '@aztec/stdlib/kernel';
|
|
9
10
|
import { KEY_PREFIXES, computeAppSecretKey, deriveKeys, derivePublicKeyFromSecretKey } from '@aztec/stdlib/keys';
|
|
11
|
+
/** Maps a key prefix to the storage suffix for the corresponding master secret key. */ function secretKeyStorageSuffix(prefix) {
|
|
12
|
+
return prefix === 'n' ? 'nhk_m' : `${prefix}sk_m`;
|
|
13
|
+
}
|
|
10
14
|
/**
|
|
11
15
|
* Used for managing keys. Can hold keys of multiple accounts.
|
|
12
16
|
*/ export class KeyStore {
|
|
13
17
|
static SCHEMA_VERSION = 1;
|
|
18
|
+
#db;
|
|
14
19
|
#keys;
|
|
15
20
|
constructor(database){
|
|
21
|
+
this.#db = database;
|
|
16
22
|
this.#keys = database.openMap('key_store');
|
|
17
23
|
}
|
|
18
24
|
/**
|
|
@@ -29,28 +35,31 @@ import { KEY_PREFIXES, computeAppSecretKey, deriveKeys, derivePublicKeyFromSecre
|
|
|
29
35
|
* @param partialAddress - The partial address of the account.
|
|
30
36
|
* @returns The account's complete address.
|
|
31
37
|
*/ async addAccount(sk, partialAddress) {
|
|
32
|
-
const {
|
|
38
|
+
const { masterNullifierHidingKey, masterIncomingViewingSecretKey, masterOutgoingViewingSecretKey, masterTaggingSecretKey, publicKeys } = await deriveKeys(sk);
|
|
33
39
|
const completeAddress = await CompleteAddress.fromSecretKeyAndPartialAddress(sk, partialAddress);
|
|
34
40
|
const { address: account } = completeAddress;
|
|
35
|
-
//
|
|
36
|
-
await this.#keys.set(`${account.toString()}-ivsk_m`, masterIncomingViewingSecretKey.toBuffer());
|
|
37
|
-
await this.#keys.set(`${account.toString()}-ovsk_m`, masterOutgoingViewingSecretKey.toBuffer());
|
|
38
|
-
await this.#keys.set(`${account.toString()}-tsk_m`, masterTaggingSecretKey.toBuffer());
|
|
39
|
-
await this.#keys.set(`${account.toString()}-nsk_m`, masterNullifierSecretKey.toBuffer());
|
|
40
|
-
await this.#keys.set(`${account.toString()}-npk_m`, publicKeys.masterNullifierPublicKey.toBuffer());
|
|
41
|
-
await this.#keys.set(`${account.toString()}-ivpk_m`, publicKeys.masterIncomingViewingPublicKey.toBuffer());
|
|
42
|
-
await this.#keys.set(`${account.toString()}-ovpk_m`, publicKeys.masterOutgoingViewingPublicKey.toBuffer());
|
|
43
|
-
await this.#keys.set(`${account.toString()}-tpk_m`, publicKeys.masterTaggingPublicKey.toBuffer());
|
|
44
|
-
// We store pk_m_hash under `account-{n/iv/ov/t}pk_m_hash` key to be able to obtain address and key prefix
|
|
45
|
-
// using the #getKeyPrefixAndAccount function later on
|
|
41
|
+
// Compute hashes before transaction
|
|
46
42
|
const masterNullifierPublicKeyHash = await publicKeys.masterNullifierPublicKey.hash();
|
|
47
|
-
await this.#keys.set(`${account.toString()}-npk_m_hash`, masterNullifierPublicKeyHash.toBuffer());
|
|
48
43
|
const masterIncomingViewingPublicKeyHash = await publicKeys.masterIncomingViewingPublicKey.hash();
|
|
49
|
-
await this.#keys.set(`${account.toString()}-ivpk_m_hash`, masterIncomingViewingPublicKeyHash.toBuffer());
|
|
50
44
|
const masterOutgoingViewingPublicKeyHash = await publicKeys.masterOutgoingViewingPublicKey.hash();
|
|
51
|
-
await this.#keys.set(`${account.toString()}-ovpk_m_hash`, masterOutgoingViewingPublicKeyHash.toBuffer());
|
|
52
45
|
const masterTaggingPublicKeyHash = await publicKeys.masterTaggingPublicKey.hash();
|
|
53
|
-
await this.#
|
|
46
|
+
await this.#db.transactionAsync(async ()=>{
|
|
47
|
+
// Naming of keys is as follows ${account}-${n/iv/ov/t}${sk/pk}_m
|
|
48
|
+
await this.#keys.set(`${account.toString()}-ivsk_m`, masterIncomingViewingSecretKey.toBuffer());
|
|
49
|
+
await this.#keys.set(`${account.toString()}-ovsk_m`, masterOutgoingViewingSecretKey.toBuffer());
|
|
50
|
+
await this.#keys.set(`${account.toString()}-tsk_m`, masterTaggingSecretKey.toBuffer());
|
|
51
|
+
await this.#keys.set(`${account.toString()}-nhk_m`, masterNullifierHidingKey.toBuffer());
|
|
52
|
+
await this.#keys.set(`${account.toString()}-npk_m`, publicKeys.masterNullifierPublicKey.toBuffer());
|
|
53
|
+
await this.#keys.set(`${account.toString()}-ivpk_m`, publicKeys.masterIncomingViewingPublicKey.toBuffer());
|
|
54
|
+
await this.#keys.set(`${account.toString()}-ovpk_m`, publicKeys.masterOutgoingViewingPublicKey.toBuffer());
|
|
55
|
+
await this.#keys.set(`${account.toString()}-tpk_m`, publicKeys.masterTaggingPublicKey.toBuffer());
|
|
56
|
+
// We store pk_m_hash under `account-{n/iv/ov/t}pk_m_hash` key to be able to obtain address and key prefix
|
|
57
|
+
// using the #getKeyPrefixAndAccount function later on
|
|
58
|
+
await this.#keys.set(`${account.toString()}-npk_m_hash`, masterNullifierPublicKeyHash.toBuffer());
|
|
59
|
+
await this.#keys.set(`${account.toString()}-ivpk_m_hash`, masterIncomingViewingPublicKeyHash.toBuffer());
|
|
60
|
+
await this.#keys.set(`${account.toString()}-ovpk_m_hash`, masterOutgoingViewingPublicKeyHash.toBuffer());
|
|
61
|
+
await this.#keys.set(`${account.toString()}-tpk_m_hash`, masterTaggingPublicKeyHash.toBuffer());
|
|
62
|
+
});
|
|
54
63
|
// At last, we return the newly derived account address
|
|
55
64
|
return completeAddress;
|
|
56
65
|
}
|
|
@@ -63,6 +72,9 @@ import { KEY_PREFIXES, computeAppSecretKey, deriveKeys, derivePublicKeyFromSecre
|
|
|
63
72
|
const accounts = allMapKeys.filter((key)=>key.endsWith('-ivsk_m')).map((key)=>key.split('-')[0]);
|
|
64
73
|
return accounts.map((account)=>AztecAddress.fromString(account));
|
|
65
74
|
}
|
|
75
|
+
/** Checks whether an account is registered in the key store. */ async hasAccount(account) {
|
|
76
|
+
return !!await this.#keys.getAsync(`${account.toString()}-ivsk_m`);
|
|
77
|
+
}
|
|
66
78
|
/**
|
|
67
79
|
* Gets the key validation request for a given master public key hash and contract address.
|
|
68
80
|
* @throws If the account corresponding to the master public key hash does not exist in the key store.
|
|
@@ -82,9 +94,10 @@ import { KEY_PREFIXES, computeAppSecretKey, deriveKeys, derivePublicKeyFromSecre
|
|
|
82
94
|
throw new Error(`Could not find ${keyPrefix}pkM for ${keyPrefix}pk_m_hash ${pkMHash.toString()}.`);
|
|
83
95
|
}
|
|
84
96
|
// Now we find the secret key for the public key
|
|
85
|
-
const
|
|
97
|
+
const skStorageSuffix = secretKeyStorageSuffix(keyPrefix);
|
|
98
|
+
const skMBuffer = await this.#keys.getAsync(`${account.toString()}-${skStorageSuffix}`);
|
|
86
99
|
if (!skMBuffer) {
|
|
87
|
-
throw new Error(`Could not find ${
|
|
100
|
+
throw new Error(`Could not find ${skStorageSuffix} for account ${account.toString()} whose address was successfully obtained with ${keyPrefix}pk_m_hash ${pkMHash.toString()}.`);
|
|
88
101
|
}
|
|
89
102
|
const skM = GrumpkinScalar.fromBuffer(skMBuffer);
|
|
90
103
|
// We sanity check that it's possible to derive the public key from the secret key
|
|
@@ -172,7 +185,7 @@ import { KEY_PREFIXES, computeAppSecretKey, deriveKeys, derivePublicKeyFromSecre
|
|
|
172
185
|
masterOutgoingViewingSecretKey.hi,
|
|
173
186
|
masterOutgoingViewingSecretKey.lo,
|
|
174
187
|
app
|
|
175
|
-
],
|
|
188
|
+
], DomainSeparator.OVSK_M);
|
|
176
189
|
}
|
|
177
190
|
/**
|
|
178
191
|
* Retrieves the sk_m corresponding to the pk_m.
|
|
@@ -182,18 +195,34 @@ import { KEY_PREFIXES, computeAppSecretKey, deriveKeys, derivePublicKeyFromSecre
|
|
|
182
195
|
* @dev Used when feeding the sk_m to the kernel circuit for keys verification.
|
|
183
196
|
*/ async getMasterSecretKey(pkM) {
|
|
184
197
|
const [keyPrefix, account] = await this.getKeyPrefixAndAccount(pkM);
|
|
185
|
-
const
|
|
198
|
+
const skStorageSuffix = secretKeyStorageSuffix(keyPrefix);
|
|
199
|
+
const secretKeyBuffer = await this.#keys.getAsync(`${account.toString()}-${skStorageSuffix}`);
|
|
186
200
|
if (!secretKeyBuffer) {
|
|
187
|
-
throw new Error(`Could not find ${
|
|
201
|
+
throw new Error(`Could not find ${skStorageSuffix} for ${keyPrefix}pk_m ${pkM.toString()}. This should not happen.`);
|
|
188
202
|
}
|
|
189
203
|
const skM = GrumpkinScalar.fromBuffer(secretKeyBuffer);
|
|
190
204
|
const derivedpkM = await derivePublicKeyFromSecretKey(skM);
|
|
191
205
|
if (!derivedpkM.equals(pkM)) {
|
|
192
|
-
throw new Error(`Could not find ${
|
|
206
|
+
throw new Error(`Could not find ${skStorageSuffix} for ${keyPrefix}pkM ${pkM.toString()} in secret keys buffer.`);
|
|
193
207
|
}
|
|
194
208
|
return Promise.resolve(skM);
|
|
195
209
|
}
|
|
196
210
|
/**
|
|
211
|
+
* Checks whether a given account has a key matching the provided master public key hash.
|
|
212
|
+
* @param account - The account address to check.
|
|
213
|
+
* @param pkMHash - The master public key hash to look for.
|
|
214
|
+
* @returns True if the account has a key with the given hash.
|
|
215
|
+
*/ async accountHasKey(account, pkMHash) {
|
|
216
|
+
const pkMHashBuffer = serializeToBuffer(pkMHash);
|
|
217
|
+
for (const prefix of KEY_PREFIXES){
|
|
218
|
+
const stored = await this.#keys.getAsync(`${account.toString()}-${prefix}pk_m_hash`);
|
|
219
|
+
if (stored && Buffer.from(stored).equals(pkMHashBuffer)) {
|
|
220
|
+
return true;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return false;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
197
226
|
* Gets the key prefix and account address for a given value.
|
|
198
227
|
* @returns A tuple containing the key prefix and account address.
|
|
199
228
|
* @dev Note that this is quite inefficient but it should not matter because there should never be too many keys
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/key-store",
|
|
3
|
-
"version": "0.0.1-commit.
|
|
3
|
+
"version": "0.0.1-commit.ff7989d6c",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": "./dest/index.js",
|
|
6
6
|
"typedocOptions": {
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
"tsconfig": "./tsconfig.json"
|
|
12
12
|
},
|
|
13
13
|
"scripts": {
|
|
14
|
-
"build": "yarn clean &&
|
|
15
|
-
"build:dev": "
|
|
14
|
+
"build": "yarn clean && ../scripts/tsc.sh",
|
|
15
|
+
"build:dev": "../scripts/tsc.sh --watch",
|
|
16
16
|
"clean": "rm -rf ./dest .tsbuildinfo",
|
|
17
17
|
"test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules ../node_modules/.bin/jest --passWithNoTests --maxWorkers=${JEST_MAX_WORKERS:-8}"
|
|
18
18
|
},
|
|
@@ -57,17 +57,17 @@
|
|
|
57
57
|
]
|
|
58
58
|
},
|
|
59
59
|
"dependencies": {
|
|
60
|
-
"@aztec/constants": "0.0.1-commit.
|
|
61
|
-
"@aztec/foundation": "0.0.1-commit.
|
|
62
|
-
"@aztec/kv-store": "0.0.1-commit.
|
|
63
|
-
"@aztec/stdlib": "0.0.1-commit.
|
|
60
|
+
"@aztec/constants": "0.0.1-commit.ff7989d6c",
|
|
61
|
+
"@aztec/foundation": "0.0.1-commit.ff7989d6c",
|
|
62
|
+
"@aztec/kv-store": "0.0.1-commit.ff7989d6c",
|
|
63
|
+
"@aztec/stdlib": "0.0.1-commit.ff7989d6c",
|
|
64
64
|
"tslib": "^2.4.0"
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|
|
67
67
|
"@jest/globals": "^30.0.0",
|
|
68
68
|
"@types/jest": "^30.0.0",
|
|
69
69
|
"@types/node": "^22.15.17",
|
|
70
|
-
"@typescript/native-preview": "7.0.0-dev.
|
|
70
|
+
"@typescript/native-preview": "7.0.0-dev.20260113.1",
|
|
71
71
|
"jest": "^30.0.0",
|
|
72
72
|
"ts-node": "^10.9.1",
|
|
73
73
|
"typescript": "^5.3.3"
|
package/src/key_store.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { poseidon2HashWithSeparator } from '@aztec/foundation/crypto';
|
|
3
|
-
import { Fr
|
|
1
|
+
import { DomainSeparator } from '@aztec/constants';
|
|
2
|
+
import { poseidon2HashWithSeparator } from '@aztec/foundation/crypto/poseidon';
|
|
3
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
4
|
+
import { GrumpkinScalar, Point } from '@aztec/foundation/curves/grumpkin';
|
|
4
5
|
import { toArray } from '@aztec/foundation/iterable';
|
|
5
6
|
import { type Bufferable, serializeToBuffer } from '@aztec/foundation/serialize';
|
|
6
7
|
import type { AztecAsyncKVStore, AztecAsyncMap } from '@aztec/kv-store';
|
|
@@ -16,14 +17,21 @@ import {
|
|
|
16
17
|
derivePublicKeyFromSecretKey,
|
|
17
18
|
} from '@aztec/stdlib/keys';
|
|
18
19
|
|
|
20
|
+
/** Maps a key prefix to the storage suffix for the corresponding master secret key. */
|
|
21
|
+
function secretKeyStorageSuffix(prefix: KeyPrefix): string {
|
|
22
|
+
return prefix === 'n' ? 'nhk_m' : `${prefix}sk_m`;
|
|
23
|
+
}
|
|
24
|
+
|
|
19
25
|
/**
|
|
20
26
|
* Used for managing keys. Can hold keys of multiple accounts.
|
|
21
27
|
*/
|
|
22
28
|
export class KeyStore {
|
|
23
29
|
public static readonly SCHEMA_VERSION = 1;
|
|
30
|
+
#db: AztecAsyncKVStore;
|
|
24
31
|
#keys: AztecAsyncMap<string, Buffer>;
|
|
25
32
|
|
|
26
33
|
constructor(database: AztecAsyncKVStore) {
|
|
34
|
+
this.#db = database;
|
|
27
35
|
this.#keys = database.openMap('key_store');
|
|
28
36
|
}
|
|
29
37
|
|
|
@@ -45,7 +53,7 @@ export class KeyStore {
|
|
|
45
53
|
*/
|
|
46
54
|
public async addAccount(sk: Fr, partialAddress: PartialAddress): Promise<CompleteAddress> {
|
|
47
55
|
const {
|
|
48
|
-
|
|
56
|
+
masterNullifierHidingKey,
|
|
49
57
|
masterIncomingViewingSecretKey,
|
|
50
58
|
masterOutgoingViewingSecretKey,
|
|
51
59
|
masterTaggingSecretKey,
|
|
@@ -55,27 +63,31 @@ export class KeyStore {
|
|
|
55
63
|
const completeAddress = await CompleteAddress.fromSecretKeyAndPartialAddress(sk, partialAddress);
|
|
56
64
|
const { address: account } = completeAddress;
|
|
57
65
|
|
|
58
|
-
//
|
|
59
|
-
await this.#keys.set(`${account.toString()}-ivsk_m`, masterIncomingViewingSecretKey.toBuffer());
|
|
60
|
-
await this.#keys.set(`${account.toString()}-ovsk_m`, masterOutgoingViewingSecretKey.toBuffer());
|
|
61
|
-
await this.#keys.set(`${account.toString()}-tsk_m`, masterTaggingSecretKey.toBuffer());
|
|
62
|
-
await this.#keys.set(`${account.toString()}-nsk_m`, masterNullifierSecretKey.toBuffer());
|
|
63
|
-
|
|
64
|
-
await this.#keys.set(`${account.toString()}-npk_m`, publicKeys.masterNullifierPublicKey.toBuffer());
|
|
65
|
-
await this.#keys.set(`${account.toString()}-ivpk_m`, publicKeys.masterIncomingViewingPublicKey.toBuffer());
|
|
66
|
-
await this.#keys.set(`${account.toString()}-ovpk_m`, publicKeys.masterOutgoingViewingPublicKey.toBuffer());
|
|
67
|
-
await this.#keys.set(`${account.toString()}-tpk_m`, publicKeys.masterTaggingPublicKey.toBuffer());
|
|
68
|
-
|
|
69
|
-
// We store pk_m_hash under `account-{n/iv/ov/t}pk_m_hash` key to be able to obtain address and key prefix
|
|
70
|
-
// using the #getKeyPrefixAndAccount function later on
|
|
66
|
+
// Compute hashes before transaction
|
|
71
67
|
const masterNullifierPublicKeyHash = await publicKeys.masterNullifierPublicKey.hash();
|
|
72
|
-
await this.#keys.set(`${account.toString()}-npk_m_hash`, masterNullifierPublicKeyHash.toBuffer());
|
|
73
68
|
const masterIncomingViewingPublicKeyHash = await publicKeys.masterIncomingViewingPublicKey.hash();
|
|
74
|
-
await this.#keys.set(`${account.toString()}-ivpk_m_hash`, masterIncomingViewingPublicKeyHash.toBuffer());
|
|
75
69
|
const masterOutgoingViewingPublicKeyHash = await publicKeys.masterOutgoingViewingPublicKey.hash();
|
|
76
|
-
await this.#keys.set(`${account.toString()}-ovpk_m_hash`, masterOutgoingViewingPublicKeyHash.toBuffer());
|
|
77
70
|
const masterTaggingPublicKeyHash = await publicKeys.masterTaggingPublicKey.hash();
|
|
78
|
-
|
|
71
|
+
|
|
72
|
+
await this.#db.transactionAsync(async () => {
|
|
73
|
+
// Naming of keys is as follows ${account}-${n/iv/ov/t}${sk/pk}_m
|
|
74
|
+
await this.#keys.set(`${account.toString()}-ivsk_m`, masterIncomingViewingSecretKey.toBuffer());
|
|
75
|
+
await this.#keys.set(`${account.toString()}-ovsk_m`, masterOutgoingViewingSecretKey.toBuffer());
|
|
76
|
+
await this.#keys.set(`${account.toString()}-tsk_m`, masterTaggingSecretKey.toBuffer());
|
|
77
|
+
await this.#keys.set(`${account.toString()}-nhk_m`, masterNullifierHidingKey.toBuffer());
|
|
78
|
+
|
|
79
|
+
await this.#keys.set(`${account.toString()}-npk_m`, publicKeys.masterNullifierPublicKey.toBuffer());
|
|
80
|
+
await this.#keys.set(`${account.toString()}-ivpk_m`, publicKeys.masterIncomingViewingPublicKey.toBuffer());
|
|
81
|
+
await this.#keys.set(`${account.toString()}-ovpk_m`, publicKeys.masterOutgoingViewingPublicKey.toBuffer());
|
|
82
|
+
await this.#keys.set(`${account.toString()}-tpk_m`, publicKeys.masterTaggingPublicKey.toBuffer());
|
|
83
|
+
|
|
84
|
+
// We store pk_m_hash under `account-{n/iv/ov/t}pk_m_hash` key to be able to obtain address and key prefix
|
|
85
|
+
// using the #getKeyPrefixAndAccount function later on
|
|
86
|
+
await this.#keys.set(`${account.toString()}-npk_m_hash`, masterNullifierPublicKeyHash.toBuffer());
|
|
87
|
+
await this.#keys.set(`${account.toString()}-ivpk_m_hash`, masterIncomingViewingPublicKeyHash.toBuffer());
|
|
88
|
+
await this.#keys.set(`${account.toString()}-ovpk_m_hash`, masterOutgoingViewingPublicKeyHash.toBuffer());
|
|
89
|
+
await this.#keys.set(`${account.toString()}-tpk_m_hash`, masterTaggingPublicKeyHash.toBuffer());
|
|
90
|
+
});
|
|
79
91
|
|
|
80
92
|
// At last, we return the newly derived account address
|
|
81
93
|
return completeAddress;
|
|
@@ -92,6 +104,11 @@ export class KeyStore {
|
|
|
92
104
|
return accounts.map(account => AztecAddress.fromString(account));
|
|
93
105
|
}
|
|
94
106
|
|
|
107
|
+
/** Checks whether an account is registered in the key store. */
|
|
108
|
+
public async hasAccount(account: AztecAddress): Promise<boolean> {
|
|
109
|
+
return !!(await this.#keys.getAsync(`${account.toString()}-ivsk_m`));
|
|
110
|
+
}
|
|
111
|
+
|
|
95
112
|
/**
|
|
96
113
|
* Gets the key validation request for a given master public key hash and contract address.
|
|
97
114
|
* @throws If the account corresponding to the master public key hash does not exist in the key store.
|
|
@@ -117,10 +134,11 @@ export class KeyStore {
|
|
|
117
134
|
}
|
|
118
135
|
|
|
119
136
|
// Now we find the secret key for the public key
|
|
120
|
-
const
|
|
137
|
+
const skStorageSuffix = secretKeyStorageSuffix(keyPrefix);
|
|
138
|
+
const skMBuffer = await this.#keys.getAsync(`${account.toString()}-${skStorageSuffix}`);
|
|
121
139
|
if (!skMBuffer) {
|
|
122
140
|
throw new Error(
|
|
123
|
-
`Could not find ${
|
|
141
|
+
`Could not find ${skStorageSuffix} for account ${account.toString()} whose address was successfully obtained with ${keyPrefix}pk_m_hash ${pkMHash.toString()}.`,
|
|
124
142
|
);
|
|
125
143
|
}
|
|
126
144
|
|
|
@@ -236,7 +254,7 @@ export class KeyStore {
|
|
|
236
254
|
|
|
237
255
|
return poseidon2HashWithSeparator(
|
|
238
256
|
[masterOutgoingViewingSecretKey.hi, masterOutgoingViewingSecretKey.lo, app],
|
|
239
|
-
|
|
257
|
+
DomainSeparator.OVSK_M,
|
|
240
258
|
);
|
|
241
259
|
}
|
|
242
260
|
|
|
@@ -250,22 +268,40 @@ export class KeyStore {
|
|
|
250
268
|
public async getMasterSecretKey(pkM: PublicKey): Promise<GrumpkinScalar> {
|
|
251
269
|
const [keyPrefix, account] = await this.getKeyPrefixAndAccount(pkM);
|
|
252
270
|
|
|
253
|
-
const
|
|
271
|
+
const skStorageSuffix = secretKeyStorageSuffix(keyPrefix);
|
|
272
|
+
const secretKeyBuffer = await this.#keys.getAsync(`${account.toString()}-${skStorageSuffix}`);
|
|
254
273
|
if (!secretKeyBuffer) {
|
|
255
274
|
throw new Error(
|
|
256
|
-
`Could not find ${
|
|
275
|
+
`Could not find ${skStorageSuffix} for ${keyPrefix}pk_m ${pkM.toString()}. This should not happen.`,
|
|
257
276
|
);
|
|
258
277
|
}
|
|
259
278
|
|
|
260
279
|
const skM = GrumpkinScalar.fromBuffer(secretKeyBuffer);
|
|
261
280
|
const derivedpkM = await derivePublicKeyFromSecretKey(skM);
|
|
262
281
|
if (!derivedpkM.equals(pkM)) {
|
|
263
|
-
throw new Error(`Could not find ${
|
|
282
|
+
throw new Error(`Could not find ${skStorageSuffix} for ${keyPrefix}pkM ${pkM.toString()} in secret keys buffer.`);
|
|
264
283
|
}
|
|
265
284
|
|
|
266
285
|
return Promise.resolve(skM);
|
|
267
286
|
}
|
|
268
287
|
|
|
288
|
+
/**
|
|
289
|
+
* Checks whether a given account has a key matching the provided master public key hash.
|
|
290
|
+
* @param account - The account address to check.
|
|
291
|
+
* @param pkMHash - The master public key hash to look for.
|
|
292
|
+
* @returns True if the account has a key with the given hash.
|
|
293
|
+
*/
|
|
294
|
+
public async accountHasKey(account: AztecAddress, pkMHash: Fr): Promise<boolean> {
|
|
295
|
+
const pkMHashBuffer = serializeToBuffer(pkMHash);
|
|
296
|
+
for (const prefix of KEY_PREFIXES) {
|
|
297
|
+
const stored = await this.#keys.getAsync(`${account.toString()}-${prefix}pk_m_hash`);
|
|
298
|
+
if (stored && Buffer.from(stored).equals(pkMHashBuffer)) {
|
|
299
|
+
return true;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
return false;
|
|
303
|
+
}
|
|
304
|
+
|
|
269
305
|
/**
|
|
270
306
|
* Gets the key prefix and account address for a given value.
|
|
271
307
|
* @returns A tuple containing the key prefix and account address.
|