Skip to content

Commit 156858f

Browse files
Format-preserving encryption capabilities (#17)
* FPE.init() * Fix UT * improve * improveSerialization * testSerialization * deleteDebugLog * . * fix * fix * add pubkey in response * delete debug log * Add public key on request * fixUT * practions
1 parent 19ab09c commit 156858f

15 files changed

+715
-218
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,9 @@
6060
"@crossmint/client-sdk-window": "1.0.0",
6161
"@crossmint/client-signers": "0.0.8",
6262
"@hpke/core": "^1.7.2",
63-
"shamir-secret-sharing": "^0.0.4",
63+
"@noble/ciphers": "^1.3.0",
6464
"bs58": "^6.0.0",
65+
"shamir-secret-sharing": "^0.0.4",
6566
"zod": "3.22.4"
6667
}
6768
}

pnpm-lock.yaml

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/services/api.test.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,13 @@ describe('CrossmintApiService', () => {
6969
const authData = { jwt: 'test-jwt', apiKey: 'test-api-key' };
7070

7171
it('should properly call createSigner with correct parameters', async () => {
72-
const data = { authId: 'test-auth-id', chainLayer: 'solana' };
72+
const data = {
73+
authId: 'test-auth-id',
74+
chainLayer: 'solana',
75+
encryptionContext: {
76+
publicKey: 'test-public-key',
77+
},
78+
};
7379
executeSpy.mockResolvedValueOnce({ success: true });
7480

7581
await apiService.createSigner(deviceId, data, authData);
@@ -78,19 +84,25 @@ describe('CrossmintApiService', () => {
7884
expect.objectContaining({
7985
authId: 'test-auth-id',
8086
chainLayer: 'solana',
87+
encryptionContext: {
88+
publicKey: 'test-public-key',
89+
},
8190
}),
8291
authData
8392
);
8493
});
8594

8695
it('should properly call sendOtp with correct parameters and return shares', async () => {
87-
const data = { otp: '123456' };
96+
const data = { otp: '123456', publicKey: 'test-public-key' };
8897
const mockResponse = { shares: { device: 'device-share', auth: 'auth-share' } };
8998
executeSpy.mockResolvedValueOnce(mockResponse);
9099

91100
const result = await apiService.sendOtp(deviceId, data, authData);
92101

93-
expect(executeSpy).toHaveBeenCalledWith(expect.objectContaining({ otp: '123456' }), authData);
102+
expect(executeSpy).toHaveBeenCalledWith(
103+
expect.objectContaining({ otp: '123456', publicKey: 'test-public-key' }),
104+
authData
105+
);
94106
expect(result).toEqual(mockResponse);
95107
});
96108
});

src/services/api.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,15 @@ export class CrossmintApiService extends XMIFService {
6464
async init() {}
6565

6666
// Zod schemas
67-
static createSignerInputSchema = z.object({ authId: z.string() });
67+
static createSignerInputSchema = z.object({
68+
authId: z.string(),
69+
encryptionContext: z.object({
70+
publicKey: z.string(),
71+
}),
72+
});
6873
static createSignerOutputSchema = z.object({});
6974

70-
static sendOtpInputSchema = z.object({ otp: z.string() });
75+
static sendOtpInputSchema = z.object({ otp: z.string(), publicKey: z.string() });
7176
static sendOtpOutputSchema = z.object({
7277
shares: z.object({
7378
device: z.string(),

src/services/encryption-consts.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { z } from 'zod';
2+
3+
export type EncryptionResult<T extends ArrayBuffer | string> = {
4+
ciphertext: T;
5+
encapsulatedKey: T;
6+
publicKey: T;
7+
};
8+
export type DecryptOptions = {
9+
validateTeeSender: boolean;
10+
};
11+
12+
export const SerializedPublicKeySchema = z.object({
13+
raw: z.string(),
14+
algorithm: z.any(),
15+
});
16+
export type SerializedPublicKey = z.infer<typeof SerializedPublicKeySchema>;
17+
18+
export const SerializedPrivateKeySchema = z.object({
19+
raw: z.any(),
20+
usages: z.array(z.custom<KeyUsage>()),
21+
algorithm: z.any(),
22+
});
23+
export type SerializedPrivateKey = z.infer<typeof SerializedPrivateKeySchema>;
24+
25+
export const AES256_KEY_SPEC: AesKeyGenParams = {
26+
name: 'AES-GCM' as const,
27+
length: 256,
28+
} as const;
29+
export const ECDH_KEY_SPEC: EcKeyGenParams = {
30+
name: 'ECDH' as const,
31+
namedCurve: 'P-384' as const,
32+
} as const;
33+
34+
export const STORAGE_KEYS = {
35+
PRIV_KEY: 'private-key',
36+
PUB_KEY: 'public-key',
37+
} as const;

0 commit comments

Comments
 (0)