-
-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
225 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
import { bls12_381 as bls } from '@noble/curves/bls12-381' | ||
|
||
import type * as Bytes from './Bytes.js' | ||
import type * as Errors from './Errors.js' | ||
import * as Hex from './Hex.js' | ||
|
||
export type Fp = bigint | ||
export type Fp2 = { c0: Fp; c1: Fp } | ||
|
||
// TODO: move to a `BlsPoint` module? | ||
export type Point<F = Fp> = { | ||
x: F | ||
y: F | ||
z: F | ||
} | ||
|
||
export type G1Point = Point<Fp> | ||
export type G2Point = Point<Fp2> | ||
|
||
export type Size = 'short' | 'long' | ||
|
||
/** Re-export of @noble/curves BLS12-381 utilities. */ | ||
Check warning on line 22 in src/Bls.ts GitHub Actions / Verify / Checks
|
||
export const noble = bls | ||
|
||
/** | ||
* Computes the BLS12-381 public key from a provided private key. | ||
* | ||
* Public Keys can be derived as a point on one of the BLS12-381 groups: | ||
* | ||
* - G1 Point (Default): | ||
* - short (48 bytes) | ||
* - computes longer G2 Signatures (96 bytes) | ||
* - G2 Point: | ||
* - long (96 bytes) | ||
* - computes short G1 Signatures (48 bytes) | ||
* | ||
* @example | ||
* ### Short G1 Public Keys (Default) | ||
* | ||
* ```ts twoslash | ||
* import { Bls } from 'ox' | ||
* | ||
* const publicKey = Bls.getPublicKey({ privateKey: '0x...' }) | ||
* // ^? | ||
* | ||
* | ||
* | ||
* | ||
* ``` | ||
* | ||
* @example | ||
* ### Long G2 Public Keys | ||
* | ||
* A G2 Public Key can be derived as a G2 point (96 bytes) using `size: 'long'`. | ||
* | ||
* This will allow you to compute G1 Signatures (48 bytes) with {@link Bls.sign}. | ||
* | ||
* ```ts twoslash | ||
* import { Bls } from 'ox' | ||
* | ||
* const publicKey = Bls.getPublicKey({ | ||
* privateKey: '0x...', | ||
* size: 'long', | ||
* }) | ||
* | ||
* publicKey | ||
* // ^? | ||
* | ||
* | ||
* | ||
* | ||
* | ||
* ``` | ||
* | ||
* @param options - The options to compute the public key. | ||
* @returns The computed public key. | ||
*/ | ||
export function getPublicKey<size extends Size = 'short'>( | ||
options: getPublicKey.Options<size>, | ||
): size extends 'short' ? G1Point : G2Point | ||
// eslint-disable-next-line jsdoc/require-jsdoc | ||
export function getPublicKey(options: getPublicKey.Options): Point<Fp | Fp2> { | ||
const { privateKey, size = 'short' } = options | ||
const group = size === 'short' ? bls.G1 : bls.G2 | ||
const { px, py, pz } = group.ProjectivePoint.fromPrivateKey( | ||
Hex.from(privateKey).slice(2), | ||
) | ||
return { x: px, y: py, z: pz } | ||
} | ||
|
||
export declare namespace getPublicKey { | ||
type Options<size extends Size = 'short'> = { | ||
/** | ||
* Private key to compute the public key from. | ||
*/ | ||
privateKey: Hex.Hex | Bytes.Bytes | ||
/** | ||
* Size of the public key to compute. | ||
* | ||
* - `'short'`: 48 bytes; computes long signatures (96 bytes) | ||
* - `'long'`: 96 bytes; computes short signatures (48 bytes) | ||
* | ||
* @default 'short' | ||
*/ | ||
size?: size | Size | undefined | ||
} | ||
|
||
type ErrorType = Hex.from.ErrorType | Errors.GlobalErrorType | ||
} | ||
|
||
/** | ||
* Generates a random BLS12-381 private key. | ||
* | ||
* @example | ||
* ```ts twoslash | ||
* import { Bls } from 'ox' | ||
* | ||
* const privateKey = Bls.randomPrivateKey() | ||
* ``` | ||
* | ||
* @param options - The options to generate the private key. | ||
* @returns The generated private key. | ||
*/ | ||
export function randomPrivateKey<as extends 'Hex' | 'Bytes' = 'Hex'>( | ||
options: randomPrivateKey.Options<as> = {}, | ||
): randomPrivateKey.ReturnType<as> { | ||
const { as = 'Hex' } = options | ||
const bytes = bls.utils.randomPrivateKey() | ||
if (as === 'Hex') return Hex.fromBytes(bytes) as never | ||
return bytes as never | ||
} | ||
|
||
export declare namespace randomPrivateKey { | ||
type Options<as extends 'Hex' | 'Bytes' = 'Hex'> = { | ||
/** | ||
* Format of the returned private key. | ||
* @default 'Hex' | ||
*/ | ||
as?: as | 'Hex' | 'Bytes' | undefined | ||
} | ||
|
||
type ReturnType<as extends 'Hex' | 'Bytes'> = | ||
| (as extends 'Bytes' ? Bytes.Bytes : never) | ||
| (as extends 'Hex' ? Hex.Hex : never) | ||
|
||
type ErrorType = Hex.fromBytes.ErrorType | Errors.GlobalErrorType | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import { Bls } from 'ox' | ||
import { describe, expect, it } from 'vitest' | ||
|
||
const privateKey = | ||
'0x527f85c60ed7402247da21f1835cea651d0954fc15b7288f096d3608400cb6ac' | ||
|
||
describe('getPublicKey', () => { | ||
it('default', () => { | ||
const publicKey = Bls.getPublicKey({ privateKey }) | ||
expect(publicKey).toMatchInlineSnapshot(` | ||
{ | ||
"x": 1952783380189056174522580903352347766701573809635723835268303492562286913265402164399416172997666069723894699105894n, | ||
"y": 3394089175947417419526317884165437122243448720528225119792553064107324599006426161993648623279289675312316462718429n, | ||
"z": 1n, | ||
} | ||
`) | ||
}) | ||
|
||
it('size: "long"', () => { | ||
const publicKey = Bls.getPublicKey({ privateKey, size: 'long' }) | ||
expect(publicKey).toMatchInlineSnapshot(` | ||
{ | ||
"x": { | ||
"c0": 355700073819052008684778820175963255205495140126954969787089018774753222070622698188835174184164179369078130885244n, | ||
"c1": 3141747483469678201696152507180044107401052508149828985947848597238369234167677882679751100991611433759974704216489n, | ||
}, | ||
"y": { | ||
"c0": 2066498625632373741693121319338450383866133445054897600869581552265032944423583015562782022208222353927807243866749n, | ||
"c1": 2094957017561088565638483770249057751981351081887405244515911122357724535677090041039038848651564427361620547334206n, | ||
}, | ||
"z": { | ||
"c0": 1n, | ||
"c1": 0n, | ||
}, | ||
} | ||
`) | ||
}) | ||
}) | ||
|
||
describe('randomPrivateKey', () => { | ||
it('default', () => { | ||
const privateKey = Bls.randomPrivateKey() | ||
expect(privateKey).toBeDefined() | ||
expect(privateKey.length).toBe(66) | ||
}) | ||
|
||
it('as: bytes', () => { | ||
const privateKey = Bls.randomPrivateKey({ as: 'Bytes' }) | ||
expect(privateKey).toBeDefined() | ||
expect(privateKey.length).toBe(32) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters