@noble/curves 0.5.1 → 0.6.0
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/README.md +49 -8
- package/lib/_shortw_utils.d.ts +11 -26
- package/lib/abstract/bls.d.ts +51 -35
- package/lib/abstract/bls.js +77 -139
- package/lib/abstract/{group.d.ts → curve.d.ts} +31 -1
- package/lib/abstract/{group.js → curve.js} +39 -2
- package/lib/abstract/edwards.d.ts +30 -81
- package/lib/abstract/edwards.js +225 -420
- package/lib/abstract/hash-to-curve.d.ts +25 -6
- package/lib/abstract/hash-to-curve.js +40 -12
- package/lib/abstract/modular.d.ts +20 -7
- package/lib/abstract/modular.js +80 -51
- package/lib/abstract/montgomery.js +3 -4
- package/lib/abstract/poseidon.d.ts +29 -0
- package/lib/abstract/poseidon.js +115 -0
- package/lib/abstract/utils.d.ts +5 -34
- package/lib/abstract/utils.js +23 -63
- package/lib/abstract/weierstrass.d.ts +56 -79
- package/lib/abstract/weierstrass.js +509 -641
- package/lib/bls12-381.d.ts +1 -0
- package/lib/bls12-381.js +75 -65
- package/lib/bn.js +1 -1
- package/lib/ed25519.d.ts +7 -5
- package/lib/ed25519.js +87 -84
- package/lib/ed448.d.ts +3 -0
- package/lib/ed448.js +88 -84
- package/lib/esm/abstract/bls.js +77 -139
- package/lib/esm/abstract/{group.js → curve.js} +37 -1
- package/lib/esm/abstract/edwards.js +223 -418
- package/lib/esm/abstract/hash-to-curve.js +38 -11
- package/lib/esm/abstract/modular.js +77 -50
- package/lib/esm/abstract/montgomery.js +4 -7
- package/lib/esm/abstract/poseidon.js +109 -0
- package/lib/esm/abstract/utils.js +21 -59
- package/lib/esm/abstract/weierstrass.js +508 -640
- package/lib/esm/bls12-381.js +86 -76
- package/lib/esm/bn.js +1 -1
- package/lib/esm/ed25519.js +85 -83
- package/lib/esm/ed448.js +86 -83
- package/lib/esm/jubjub.js +6 -5
- package/lib/esm/p256.js +11 -9
- package/lib/esm/p384.js +11 -9
- package/lib/esm/p521.js +13 -12
- package/lib/esm/secp256k1.js +118 -157
- package/lib/esm/stark.js +104 -39
- package/lib/jubjub.d.ts +3 -2
- package/lib/jubjub.js +6 -5
- package/lib/p192.d.ts +22 -52
- package/lib/p224.d.ts +22 -52
- package/lib/p256.d.ts +25 -52
- package/lib/p256.js +13 -10
- package/lib/p384.d.ts +25 -52
- package/lib/p384.js +13 -10
- package/lib/p521.d.ts +25 -52
- package/lib/p521.js +15 -13
- package/lib/secp256k1.d.ts +26 -42
- package/lib/secp256k1.js +118 -157
- package/lib/stark.d.ts +36 -21
- package/lib/stark.js +107 -39
- package/package.json +14 -9
package/README.md
CHANGED
|
@@ -6,7 +6,9 @@ Minimal, auditable JS implementation of elliptic curve cryptography.
|
|
|
6
6
|
- ECDSA, EdDSA, Schnorr, BLS signature schemes, ECDH key agreement
|
|
7
7
|
- [hash to curve](https://datatracker.ietf.org/doc/draft-irtf-cfrg-hash-to-curve/)
|
|
8
8
|
for encoding or hashing an arbitrary string to a point on an elliptic curve
|
|
9
|
-
-
|
|
9
|
+
- [Poseidon](https://www.poseidon-hash.info) ZK-friendly hash
|
|
10
|
+
- Auditable
|
|
11
|
+
- 🏎 [Ultra-fast](#speed), hand-optimized for caveats of JS engines
|
|
10
12
|
- 🔍 Unique tests ensure correctness. Wycheproof vectors included
|
|
11
13
|
- 🔻 Tree-shaking-friendly: there is no entry point, which ensures small size of your app
|
|
12
14
|
|
|
@@ -24,7 +26,6 @@ Curves incorporate work from previous noble packages
|
|
|
24
26
|
[ed25519](https://github.com/paulmillr/noble-ed25519),
|
|
25
27
|
[bls12-381](https://github.com/paulmillr/noble-bls12-381)),
|
|
26
28
|
which had security audits and were developed from 2019 to 2022.
|
|
27
|
-
The goal is to replace them with lean UMD builds based on single-codebase noble-curves.
|
|
28
29
|
|
|
29
30
|
### This library belongs to _noble_ crypto
|
|
30
31
|
|
|
@@ -88,6 +89,7 @@ To define a custom curve, check out API below.
|
|
|
88
89
|
- [abstract/montgomery: Montgomery curve](#abstractmontgomery-montgomery-curve)
|
|
89
90
|
- [abstract/weierstrass: Short Weierstrass curve](#abstractweierstrass-short-weierstrass-curve)
|
|
90
91
|
- [abstract/hash-to-curve: Hashing strings to curve points](#abstracthash-to-curve-hashing-strings-to-curve-points)
|
|
92
|
+
- [abstract/poseidon: Poseidon hash](#abstractposeidon-poseidon-hash)
|
|
91
93
|
- [abstract/modular](#abstractmodular)
|
|
92
94
|
- [abstract/utils](#abstractutils)
|
|
93
95
|
|
|
@@ -201,8 +203,6 @@ export type CurveFn = {
|
|
|
201
203
|
ExtendedPoint: ExtendedPointConstructor;
|
|
202
204
|
Signature: SignatureConstructor;
|
|
203
205
|
utils: {
|
|
204
|
-
mod: (a: bigint, b?: bigint) => bigint;
|
|
205
|
-
invert: (number: bigint, modulo?: bigint) => bigint;
|
|
206
206
|
randomPrivateKey: () => Uint8Array;
|
|
207
207
|
getExtendedPublicKey: (key: PrivKey) => {
|
|
208
208
|
head: Uint8Array;
|
|
@@ -304,20 +304,18 @@ const shared = secp256k1.getSharedSecret(key, someonesPubkey);
|
|
|
304
304
|
export type CurveFn = {
|
|
305
305
|
CURVE: ReturnType<typeof validateOpts>;
|
|
306
306
|
getPublicKey: (privateKey: PrivKey, isCompressed?: boolean) => Uint8Array;
|
|
307
|
-
getSharedSecret: (privateA: PrivKey, publicB:
|
|
307
|
+
getSharedSecret: (privateA: PrivKey, publicB: Hex, isCompressed?: boolean) => Uint8Array;
|
|
308
308
|
sign: (msgHash: Hex, privKey: PrivKey, opts?: SignOpts) => SignatureType;
|
|
309
309
|
verify: (
|
|
310
310
|
signature: Hex | SignatureType,
|
|
311
311
|
msgHash: Hex,
|
|
312
|
-
publicKey:
|
|
312
|
+
publicKey: Hex,
|
|
313
313
|
opts?: { lowS?: boolean }
|
|
314
314
|
) => boolean;
|
|
315
315
|
Point: PointConstructor;
|
|
316
316
|
ProjectivePoint: ProjectivePointConstructor;
|
|
317
317
|
Signature: SignatureConstructor;
|
|
318
318
|
utils: {
|
|
319
|
-
mod: (a: bigint) => bigint;
|
|
320
|
-
invert: (number: bigint) => bigint;
|
|
321
319
|
isValidPrivateKey(privateKey: PrivKey): boolean;
|
|
322
320
|
hashToPrivateKey: (hash: Hex) => Uint8Array;
|
|
323
321
|
randomPrivateKey: () => Uint8Array;
|
|
@@ -373,6 +371,30 @@ hashes arbitrary-length byte strings to a list of one or more elements of a fini
|
|
|
373
371
|
};
|
|
374
372
|
```
|
|
375
373
|
|
|
374
|
+
### abstract/poseidon: Poseidon hash
|
|
375
|
+
|
|
376
|
+
Implements [Poseidon](https://www.poseidon-hash.info) ZK-friendly hash.
|
|
377
|
+
|
|
378
|
+
There are many poseidon instances with different constants. We don't provide them,
|
|
379
|
+
but we provide ability to specify them manually. For actual usage, check out
|
|
380
|
+
stark curve source code.
|
|
381
|
+
|
|
382
|
+
```ts
|
|
383
|
+
import { poseidon } from '@noble/curves/abstract/poseidon';
|
|
384
|
+
|
|
385
|
+
type PoseidonOpts = {
|
|
386
|
+
Fp: Field<bigint>;
|
|
387
|
+
t: number;
|
|
388
|
+
roundsFull: number;
|
|
389
|
+
roundsPartial: number;
|
|
390
|
+
sboxPower?: number;
|
|
391
|
+
reversePartialPowIdx?: boolean; // Hack for stark
|
|
392
|
+
mds: bigint[][];
|
|
393
|
+
roundConstants: bigint[][];
|
|
394
|
+
};
|
|
395
|
+
const instance = poseidon(opts: PoseidonOpts);
|
|
396
|
+
```
|
|
397
|
+
|
|
376
398
|
### abstract/modular
|
|
377
399
|
|
|
378
400
|
Modular arithmetics utilities.
|
|
@@ -462,6 +484,25 @@ verify
|
|
|
462
484
|
noble x 698 ops/sec @ 1ms/op
|
|
463
485
|
```
|
|
464
486
|
|
|
487
|
+
## Upgrading
|
|
488
|
+
|
|
489
|
+
Differences from @noble/secp256k1 1.7:
|
|
490
|
+
|
|
491
|
+
1. Different double() formula (but same addition)
|
|
492
|
+
2. Different sqrt() function
|
|
493
|
+
3. DRBG supports outputLen bigger than outputLen of hmac
|
|
494
|
+
4. Support for different hash functions
|
|
495
|
+
|
|
496
|
+
Differences from @noble/ed25519 1.7:
|
|
497
|
+
|
|
498
|
+
1. Variable field element lengths between EDDSA/ECDH:
|
|
499
|
+
EDDSA (RFC8032) is 456 bits / 57 bytes, ECDH (RFC7748) is 448 bits / 56 bytes
|
|
500
|
+
2. Different addition formula (doubling is same)
|
|
501
|
+
3. uvRatio differs between curves (half-expected, not only pow fn changes)
|
|
502
|
+
4. Point decompression code is different (unexpected), now using generalized formula
|
|
503
|
+
5. Domain function was no-op for ed25519, but adds some data even with empty context for ed448
|
|
504
|
+
|
|
505
|
+
|
|
465
506
|
## Contributing & testing
|
|
466
507
|
|
|
467
508
|
1. Clone the repository
|
package/lib/_shortw_utils.d.ts
CHANGED
|
@@ -32,41 +32,26 @@ export declare function createCurve(curveDef: CurveDef, defHash: CHash): Readonl
|
|
|
32
32
|
k2: bigint;
|
|
33
33
|
};
|
|
34
34
|
} | undefined;
|
|
35
|
-
readonly isTorsionFree?: ((c: import("./abstract/weierstrass.js").
|
|
36
|
-
readonly clearCofactor?: ((c: import("./abstract/weierstrass.js").
|
|
37
|
-
readonly htfDefaults?: import("./abstract/hash-to-curve.js").htfOpts | undefined;
|
|
38
|
-
readonly mapToCurve?: ((scalar: bigint[]) => {
|
|
39
|
-
x: bigint;
|
|
40
|
-
y: bigint;
|
|
41
|
-
}) | undefined;
|
|
35
|
+
readonly isTorsionFree?: ((c: import("./abstract/weierstrass.js").ProjConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjPointType<bigint>) => boolean) | undefined;
|
|
36
|
+
readonly clearCofactor?: ((c: import("./abstract/weierstrass.js").ProjConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjPointType<bigint>) => import("./abstract/weierstrass.js").ProjPointType<bigint>) | undefined;
|
|
42
37
|
lowS: boolean;
|
|
43
38
|
readonly hash: CHash;
|
|
44
39
|
readonly hmac: (key: Uint8Array, ...messages: Uint8Array[]) => Uint8Array;
|
|
45
40
|
readonly randomBytes: (bytesLength?: number | undefined) => Uint8Array;
|
|
46
|
-
readonly
|
|
41
|
+
readonly bits2int?: ((bytes: Uint8Array) => bigint) | undefined;
|
|
42
|
+
readonly bits2int_modN?: ((bytes: Uint8Array) => bigint) | undefined;
|
|
47
43
|
}>;
|
|
48
44
|
getPublicKey: (privateKey: import("./abstract/utils.js").PrivKey, isCompressed?: boolean | undefined) => Uint8Array;
|
|
49
|
-
getSharedSecret: (privateA: import("./abstract/utils.js").PrivKey, publicB: import("./abstract/
|
|
50
|
-
sign: (msgHash: import("./abstract/utils.js").Hex, privKey: import("./abstract/utils.js").PrivKey, opts?:
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
} | undefined) => boolean;
|
|
57
|
-
Point: import("./abstract/weierstrass.js").PointConstructor<bigint>;
|
|
58
|
-
ProjectivePoint: import("./abstract/weierstrass.js").ProjectiveConstructor<bigint>;
|
|
45
|
+
getSharedSecret: (privateA: import("./abstract/utils.js").PrivKey, publicB: import("./abstract/utils.js").Hex, isCompressed?: boolean | undefined) => Uint8Array;
|
|
46
|
+
sign: (msgHash: import("./abstract/utils.js").Hex, privKey: import("./abstract/utils.js").PrivKey, opts?: import("./abstract/weierstrass.js").SignOpts | undefined) => import("./abstract/weierstrass.js").SignatureType;
|
|
47
|
+
verify: (signature: import("./abstract/utils.js").Hex | {
|
|
48
|
+
r: bigint;
|
|
49
|
+
s: bigint;
|
|
50
|
+
}, msgHash: import("./abstract/utils.js").Hex, publicKey: import("./abstract/utils.js").Hex, opts?: import("./abstract/weierstrass.js").VerOpts | undefined) => boolean;
|
|
51
|
+
ProjectivePoint: import("./abstract/weierstrass.js").ProjConstructor<bigint>;
|
|
59
52
|
Signature: import("./abstract/weierstrass.js").SignatureConstructor;
|
|
60
53
|
utils: {
|
|
61
|
-
mod: (a: bigint, b?: bigint | undefined) => bigint;
|
|
62
|
-
invert: (number: bigint, modulo?: bigint | undefined) => bigint;
|
|
63
|
-
_bigintToBytes: (num: bigint) => Uint8Array;
|
|
64
|
-
_bigintToString: (num: bigint) => string;
|
|
65
54
|
_normalizePrivateKey: (key: import("./abstract/utils.js").PrivKey) => bigint;
|
|
66
|
-
_normalizePublicKey: (publicKey: import("./abstract/weierstrass.js").PubKey) => import("./abstract/weierstrass.js").PointType<bigint>;
|
|
67
|
-
_isWithinCurveOrder: (num: bigint) => boolean;
|
|
68
|
-
_isValidFieldElement: (num: bigint) => boolean;
|
|
69
|
-
_weierstrassEquation: (x: bigint) => bigint;
|
|
70
55
|
isValidPrivateKey(privateKey: import("./abstract/utils.js").PrivKey): boolean;
|
|
71
56
|
hashToPrivateKey: (hash: import("./abstract/utils.js").Hex) => Uint8Array;
|
|
72
57
|
randomPrivateKey: () => Uint8Array;
|
package/lib/abstract/bls.d.ts
CHANGED
|
@@ -1,24 +1,41 @@
|
|
|
1
1
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
/**
|
|
3
|
+
* BLS (Barreto-Lynn-Scott) family of pairing-friendly curves.
|
|
4
|
+
* Implements BLS (Boneh-Lynn-Shacham) signatures.
|
|
5
|
+
* Consists of two curves: G1 and G2:
|
|
6
|
+
* - G1 is a subgroup of (x, y) E(Fq) over y² = x³ + 4.
|
|
7
|
+
* - G2 is a subgroup of ((x₁, x₂+i), (y₁, y₂+i)) E(Fq²) over y² = x³ + 4(1 + i) where i is √-1
|
|
8
|
+
* - Gt, created by bilinear (ate) pairing e(G1, G2), consists of p-th roots of unity in
|
|
9
|
+
* Fq^k where k is embedding degree. Only degree 12 is currently supported, 24 is not.
|
|
10
|
+
* Pairing is used to aggregate and verify signatures.
|
|
11
|
+
* We are using Fp for private keys (shorter) and Fp₂ for signatures (longer).
|
|
12
|
+
* Some projects may prefer to swap this relation, it is not supported for now.
|
|
13
|
+
*/
|
|
14
|
+
import { AffinePoint } from './curve.js';
|
|
15
|
+
import { Field } from './modular.js';
|
|
16
|
+
import { Hex, PrivKey, CHash } from './utils.js';
|
|
17
|
+
import * as htf from './hash-to-curve.js';
|
|
18
|
+
import { CurvePointsType, ProjPointType as ProjPointType, CurvePointsRes } from './weierstrass.js';
|
|
7
19
|
declare type Fp = bigint;
|
|
8
20
|
export declare type SignatureCoder<Fp2> = {
|
|
9
|
-
decode(hex: Hex):
|
|
10
|
-
encode(point:
|
|
21
|
+
decode(hex: Hex): ProjPointType<Fp2>;
|
|
22
|
+
encode(point: ProjPointType<Fp2>): Uint8Array;
|
|
11
23
|
};
|
|
12
24
|
export declare type CurveType<Fp, Fp2, Fp6, Fp12> = {
|
|
13
25
|
r: bigint;
|
|
14
|
-
G1: Omit<CurvePointsType<Fp>, 'n'
|
|
26
|
+
G1: Omit<CurvePointsType<Fp>, 'n'> & {
|
|
27
|
+
mapToCurve: htf.MapToCurve<Fp>;
|
|
28
|
+
htfDefaults: htf.Opts;
|
|
29
|
+
};
|
|
15
30
|
G2: Omit<CurvePointsType<Fp2>, 'n'> & {
|
|
16
31
|
Signature: SignatureCoder<Fp2>;
|
|
32
|
+
mapToCurve: htf.MapToCurve<Fp2>;
|
|
33
|
+
htfDefaults: htf.Opts;
|
|
17
34
|
};
|
|
18
35
|
x: bigint;
|
|
19
|
-
Fp:
|
|
20
|
-
Fr:
|
|
21
|
-
Fp2:
|
|
36
|
+
Fp: Field<Fp>;
|
|
37
|
+
Fr: Field<bigint>;
|
|
38
|
+
Fp2: Field<Fp2> & {
|
|
22
39
|
reim: (num: Fp2) => {
|
|
23
40
|
re: bigint;
|
|
24
41
|
im: bigint;
|
|
@@ -26,54 +43,53 @@ export declare type CurveType<Fp, Fp2, Fp6, Fp12> = {
|
|
|
26
43
|
multiplyByB: (num: Fp2) => Fp2;
|
|
27
44
|
frobeniusMap(num: Fp2, power: number): Fp2;
|
|
28
45
|
};
|
|
29
|
-
Fp6:
|
|
30
|
-
Fp12:
|
|
46
|
+
Fp6: Field<Fp6>;
|
|
47
|
+
Fp12: Field<Fp12> & {
|
|
31
48
|
frobeniusMap(num: Fp12, power: number): Fp12;
|
|
32
49
|
multiplyBy014(num: Fp12, o0: Fp2, o1: Fp2, o4: Fp2): Fp12;
|
|
33
50
|
conjugate(num: Fp12): Fp12;
|
|
34
51
|
finalExponentiate(num: Fp12): Fp12;
|
|
35
52
|
};
|
|
36
|
-
htfDefaults:
|
|
37
|
-
hash:
|
|
53
|
+
htfDefaults: htf.Opts;
|
|
54
|
+
hash: CHash;
|
|
38
55
|
randomBytes: (bytesLength?: number) => Uint8Array;
|
|
39
56
|
};
|
|
40
57
|
export declare type CurveFn<Fp, Fp2, Fp6, Fp12> = {
|
|
41
58
|
CURVE: CurveType<Fp, Fp2, Fp6, Fp12>;
|
|
42
|
-
Fr:
|
|
43
|
-
Fp:
|
|
44
|
-
Fp2:
|
|
45
|
-
Fp6:
|
|
46
|
-
Fp12:
|
|
59
|
+
Fr: Field<bigint>;
|
|
60
|
+
Fp: Field<Fp>;
|
|
61
|
+
Fp2: Field<Fp2>;
|
|
62
|
+
Fp6: Field<Fp6>;
|
|
63
|
+
Fp12: Field<Fp12>;
|
|
47
64
|
G1: CurvePointsRes<Fp>;
|
|
48
65
|
G2: CurvePointsRes<Fp2>;
|
|
49
66
|
Signature: SignatureCoder<Fp2>;
|
|
50
67
|
millerLoop: (ell: [Fp2, Fp2, Fp2][], g1: [Fp, Fp]) => Fp12;
|
|
51
|
-
calcPairingPrecomputes: (
|
|
52
|
-
|
|
68
|
+
calcPairingPrecomputes: (p: AffinePoint<Fp2>) => [Fp2, Fp2, Fp2][];
|
|
69
|
+
hashToCurve: {
|
|
70
|
+
G1: ReturnType<(typeof htf.hashToCurve<Fp>)>;
|
|
71
|
+
G2: ReturnType<(typeof htf.hashToCurve<Fp2>)>;
|
|
72
|
+
};
|
|
73
|
+
pairing: (P: ProjPointType<Fp>, Q: ProjPointType<Fp2>, withFinalExponent?: boolean) => Fp12;
|
|
53
74
|
getPublicKey: (privateKey: PrivKey) => Uint8Array;
|
|
54
75
|
sign: {
|
|
55
76
|
(message: Hex, privateKey: PrivKey): Uint8Array;
|
|
56
|
-
(message:
|
|
77
|
+
(message: ProjPointType<Fp2>, privateKey: PrivKey): ProjPointType<Fp2>;
|
|
57
78
|
};
|
|
58
|
-
verify: (signature: Hex |
|
|
79
|
+
verify: (signature: Hex | ProjPointType<Fp2>, message: Hex | ProjPointType<Fp2>, publicKey: Hex | ProjPointType<Fp>) => boolean;
|
|
59
80
|
aggregatePublicKeys: {
|
|
60
81
|
(publicKeys: Hex[]): Uint8Array;
|
|
61
|
-
(publicKeys:
|
|
82
|
+
(publicKeys: ProjPointType<Fp>[]): ProjPointType<Fp>;
|
|
62
83
|
};
|
|
63
84
|
aggregateSignatures: {
|
|
64
85
|
(signatures: Hex[]): Uint8Array;
|
|
65
|
-
(signatures:
|
|
86
|
+
(signatures: ProjPointType<Fp2>[]): ProjPointType<Fp2>;
|
|
66
87
|
};
|
|
67
|
-
verifyBatch: (signature: Hex |
|
|
88
|
+
verifyBatch: (signature: Hex | ProjPointType<Fp2>, messages: (Hex | ProjPointType<Fp2>)[], publicKeys: (Hex | ProjPointType<Fp>)[]) => boolean;
|
|
68
89
|
utils: {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
hashToField: typeof hash_to_field;
|
|
73
|
-
expandMessageXMD: typeof expand_message_xmd;
|
|
74
|
-
mod: typeof mod.mod;
|
|
75
|
-
getDSTLabel: () => string;
|
|
76
|
-
setDSTLabel(newLabel: string): void;
|
|
90
|
+
stringToBytes: typeof htf.stringToBytes;
|
|
91
|
+
hashToField: typeof htf.hash_to_field;
|
|
92
|
+
expandMessageXMD: typeof htf.expand_message_xmd;
|
|
77
93
|
};
|
|
78
94
|
};
|
|
79
95
|
export declare function bls<Fp2, Fp6, Fp12>(CURVE: CurveType<Fp, Fp2, Fp6, Fp12>): CurveFn<Fp, Fp2, Fp6, Fp12>;
|