Skip to content

Commit 33906ca

Browse files
authored
feat: add raw key formats (raw-public, raw-private, raw-seed) (#1034)
1 parent cacf92a commit 33906ca

17 files changed

Lines changed: 1035 additions & 48 deletions

File tree

example/src/hooks/useTestsList.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import '../tests/keys/generate_key';
2525
import '../tests/keys/generate_keypair';
2626
import '../tests/keys/keyobject_from_tocryptokey_tests';
2727
import '../tests/keys/public_cipher';
28+
import '../tests/keys/raw_key_formats';
2829
import '../tests/keys/sign_verify_error_queue';
2930
import '../tests/keys/sign_verify_oneshot';
3031
import '../tests/keys/sign_verify_streaming';
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
import {
2+
Buffer,
3+
createPrivateKey,
4+
createPublicKey,
5+
generateKeyPair,
6+
generateKeyPairSync,
7+
PrivateKeyObject,
8+
} from 'react-native-quick-crypto';
9+
import { expect } from 'chai';
10+
import { test } from '../util';
11+
12+
const SUITE = 'keys.rawFormats';
13+
14+
type GenerateRawResult = {
15+
publicKey: ArrayBuffer | Buffer;
16+
privateKey: ArrayBuffer | Buffer;
17+
};
18+
19+
function generateKeyPairAsync(
20+
type: 'ec' | 'ed25519' | 'ed448' | 'x25519' | 'x448',
21+
options: object,
22+
): Promise<GenerateRawResult> {
23+
return new Promise((resolve, reject) => {
24+
generateKeyPair(type, options, (err, publicKey, privateKey) => {
25+
if (err) reject(err);
26+
else
27+
resolve({
28+
publicKey: publicKey as ArrayBuffer | Buffer,
29+
privateKey: privateKey as ArrayBuffer | Buffer,
30+
});
31+
});
32+
});
33+
}
34+
35+
// --- KeyObject.export with raw formats ---
36+
37+
test(SUITE, 'PublicKeyObject.export raw-public for X25519', async () => {
38+
const { publicKey, privateKey } = generateKeyPairSync('x25519');
39+
const rawPub = publicKey.export({ format: 'raw-public' });
40+
const rawPriv = privateKey.export({ format: 'raw-private' });
41+
expect(rawPub).to.be.instanceOf(Buffer);
42+
expect(rawPriv).to.be.instanceOf(Buffer);
43+
expect(rawPub.length).to.equal(32);
44+
expect(rawPriv.length).to.equal(32);
45+
});
46+
47+
test(SUITE, 'PublicKeyObject.export raw-public for Ed25519', async () => {
48+
const { publicKey, privateKey } = generateKeyPairSync('ed25519');
49+
const rawPub = publicKey.export({ format: 'raw-public' });
50+
const rawPriv = privateKey.export({ format: 'raw-private' });
51+
expect(rawPub.length).to.equal(32);
52+
expect(rawPriv.length).to.equal(32);
53+
});
54+
55+
test(SUITE, 'PublicKeyObject.export raw-public for EC P-256', async () => {
56+
const { publicKey, privateKey } = generateKeyPairSync('ec', {
57+
namedCurve: 'P-256',
58+
});
59+
const uncompressed = publicKey.export({ format: 'raw-public' });
60+
expect(uncompressed.length).to.equal(65);
61+
expect(uncompressed[0]).to.equal(0x04);
62+
63+
const compressed = publicKey.export({
64+
format: 'raw-public',
65+
type: 'compressed',
66+
});
67+
expect(compressed.length).to.equal(33);
68+
expect(compressed[0] === 0x02 || compressed[0] === 0x03).to.equal(true);
69+
70+
const rawPriv = privateKey.export({ format: 'raw-private' });
71+
expect(rawPriv.length).to.equal(32);
72+
});
73+
74+
test(SUITE, 'PrivateKeyObject.export raw-seed for ML-DSA-44', async () => {
75+
// ML-DSA may not be supported on all OpenSSL builds — guard.
76+
let privateKey: PrivateKeyObject;
77+
try {
78+
({ privateKey } = generateKeyPairSync('ml-dsa-44'));
79+
} catch {
80+
return; // skip if not supported
81+
}
82+
if (!(privateKey instanceof PrivateKeyObject)) return;
83+
const seed = privateKey.export({ format: 'raw-seed' });
84+
expect(seed).to.be.instanceOf(Buffer);
85+
expect(seed.length).to.be.greaterThan(0);
86+
});
87+
88+
// --- createPublicKey / createPrivateKey with raw formats ---
89+
90+
test(SUITE, 'createPublicKey raw-public for X25519', async () => {
91+
const { publicKey } = await generateKeyPairAsync('x25519', {
92+
publicKeyEncoding: { format: 'raw-public' },
93+
privateKeyEncoding: { format: 'raw-private' },
94+
});
95+
96+
const pub = createPublicKey({
97+
key: publicKey as Buffer,
98+
format: 'raw-public',
99+
asymmetricKeyType: 'x25519',
100+
});
101+
expect(pub.type).to.equal('public');
102+
expect(pub.asymmetricKeyType).to.equal('x25519');
103+
104+
const reExported = pub.export({ format: 'raw-public' });
105+
expect(Buffer.compare(reExported, publicKey as Buffer)).to.equal(0);
106+
});
107+
108+
test(SUITE, 'createPrivateKey raw-private for Ed25519', async () => {
109+
const { privateKey } = await generateKeyPairAsync('ed25519', {
110+
publicKeyEncoding: { format: 'raw-public' },
111+
privateKeyEncoding: { format: 'raw-private' },
112+
});
113+
114+
const priv = createPrivateKey({
115+
key: privateKey as Buffer,
116+
format: 'raw-private',
117+
asymmetricKeyType: 'ed25519',
118+
});
119+
expect(priv.type).to.equal('private');
120+
expect(priv.asymmetricKeyType).to.equal('ed25519');
121+
122+
const reExported = priv.export({ format: 'raw-private' });
123+
expect(Buffer.compare(reExported, privateKey as Buffer)).to.equal(0);
124+
});
125+
126+
test(SUITE, 'createPublicKey raw-public EC P-256 round-trip', async () => {
127+
const { publicKey } = await generateKeyPairAsync('ec', {
128+
namedCurve: 'P-256',
129+
publicKeyEncoding: { format: 'raw-public' },
130+
privateKeyEncoding: { format: 'raw-private' },
131+
});
132+
133+
const pub = createPublicKey({
134+
key: publicKey as Buffer,
135+
format: 'raw-public',
136+
asymmetricKeyType: 'ec',
137+
namedCurve: 'P-256',
138+
});
139+
expect(pub.type).to.equal('public');
140+
expect(pub.asymmetricKeyType).to.equal('ec');
141+
142+
const reExported = pub.export({ format: 'raw-public' });
143+
expect(Buffer.compare(reExported, publicKey as Buffer)).to.equal(0);
144+
});
145+
146+
test(SUITE, 'createPrivateKey raw-private EC P-256 round-trip', async () => {
147+
const { privateKey } = await generateKeyPairAsync('ec', {
148+
namedCurve: 'P-256',
149+
publicKeyEncoding: { format: 'raw-public' },
150+
privateKeyEncoding: { format: 'raw-private' },
151+
});
152+
153+
const priv = createPrivateKey({
154+
key: privateKey as Buffer,
155+
format: 'raw-private',
156+
asymmetricKeyType: 'ec',
157+
namedCurve: 'P-256',
158+
});
159+
expect(priv.type).to.equal('private');
160+
expect(priv.asymmetricKeyType).to.equal('ec');
161+
162+
const reExported = priv.export({ format: 'raw-private' });
163+
expect(Buffer.compare(reExported, privateKey as Buffer)).to.equal(0);
164+
});
165+
166+
// --- generateKeyPair raw output ---
167+
168+
test(SUITE, 'generateKeyPairSync x25519 with raw-public output', () => {
169+
const { publicKey, privateKey } = generateKeyPairSync('x25519', {
170+
publicKeyEncoding: { format: 'raw-public' },
171+
privateKeyEncoding: { format: 'raw-private' },
172+
});
173+
expect(Buffer.from(publicKey as ArrayBuffer).length).to.equal(32);
174+
expect(Buffer.from(privateKey as ArrayBuffer).length).to.equal(32);
175+
});
176+
177+
test(SUITE, 'generateKeyPair ec compressed raw-public', async () => {
178+
const { publicKey } = await generateKeyPairAsync('ec', {
179+
namedCurve: 'P-256',
180+
publicKeyEncoding: { format: 'raw-public', type: 'compressed' },
181+
privateKeyEncoding: { format: 'raw-private' },
182+
});
183+
const buf = Buffer.from(publicKey as ArrayBuffer);
184+
expect(buf.length).to.equal(33);
185+
expect(buf[0] === 0x02 || buf[0] === 0x03).to.equal(true);
186+
});

0 commit comments

Comments
 (0)