Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/dkg-manager.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Notes
When a single dealer generates all shares and the group key.

```ts
import DKGManager from '../src/manager/dkg'
import { DKGManager } from '../src/manager/dkg'

const dkg = new DKGManager()
const secret = 0x43583e33fb2f47faa243b5cdf8cb251f7e9482f0386064901ae0c5e2134b78fn
Expand Down
2 changes: 1 addition & 1 deletion docs/signing-manager.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Helper methods
## Minimal E2E usage (t-of-n)

```ts
import FROSTSigningManager from '../src/manager/signing'
import { FROSTSigningManager } from '../src/manager/signing'
import { eddsaBuild } from '../src' // provides verifyPoseidon
import { bigIntToBuffer } from '@zk-kit/utils'

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@railgun-reloaded/curves-lite",
"version": "0.2.9",
"version": "0.2.14",
"description": "Dependency light version of railgun curves functionality.",
"main": "./dist/cjs/index.js",
"module": "./dist/esm/index.js",
Expand Down
9 changes: 4 additions & 5 deletions src/eddsa/babyposeidon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,18 +38,17 @@ class EddsaPoseidon extends RailJubCurvePoint {
// misc helpers
packPoint (point: Point<bigint>): Uint8Array {
const result = packPublicKey(point)
return hexToBytes(result.toString(16))
return hexToBytes(result.toString(16).padStart(64, '0'))
}

unpackPoint (bytesIn: Uint8Array): Point<bigint> | null {
const formatted = BigInt('0x' + bytesToHex(bytesIn))
const formatted = BigInt('0x' + bytesToHex(bytesIn).padStart(64, '0'))
const result = unpackPublicKey(formatted)
return result
}
}

const eddsaBuild = new EddsaPoseidon()

export type { Signature }
export { EddsaPoseidon }
export default eddsaBuild
export type { Signature, SignatureHex }
export { EddsaPoseidon, eddsaBuild }
5 changes: 2 additions & 3 deletions src/eddsa/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import eddsaBuild from './babyposeidon.js'
import { EddsaPoseidon, eddsaBuild } from './babyposeidon.js'

export { EddsaPoseidon } from './babyposeidon.js'
export { eddsaBuild }
export { EddsaPoseidon, eddsaBuild }
4 changes: 2 additions & 2 deletions src/frost/babyfrost.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type { Point } from '@zk-kit/baby-jubjub'
import { addPoint } from '@zk-kit/baby-jubjub'

import { RailJubCurvePoint } from '../curve.js'
import RFC9591Hasher from '../hashing.js'
import { RFC9591Hasher } from '../hashing.js'

import type { BindingFactor, Bindings, Commitment, NoncePair } from './types.js'

Expand Down Expand Up @@ -212,7 +212,7 @@ class BabyFROST extends RailJubCurvePoint {
}

const frost = new BabyFROST()
export { frost }
export { frost, BabyFROST }

// export type { LocalNonces, CommitmentPublic, PartialSignature, AggregateSignature }
export default BabyFROST
4 changes: 2 additions & 2 deletions src/frost/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import BabyFROST, { frost } from './babyfrost.js'
import TrustedDKG from './trusted-dkg.js'
import { BabyFROST, frost } from './babyfrost.js'
import { TrustedDKG } from './trusted-dkg.js'

export { BabyFROST, frost, TrustedDKG }
4 changes: 2 additions & 2 deletions src/frost/trusted-dkg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type { Point } from '@zk-kit/baby-jubjub'
import { addPoint, mulPointEscalar } from '@zk-kit/baby-jubjub'

import { RailJubCurvePoint } from '../curve.js'
import RFC9591Hasher from '../hashing.js'
import { RFC9591Hasher } from '../hashing.js'

import type { EncryptedShare } from './types.js'

Expand Down Expand Up @@ -324,4 +324,4 @@ class TrustedDKG extends RailJubCurvePoint {
}
}

export default TrustedDKG
export { TrustedDKG }
5 changes: 3 additions & 2 deletions src/hashing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type { Point } from '@zk-kit/baby-jubjub'
import { leBigIntToBuffer, leBufferToBigInt } from '@zk-kit/utils'
import { poseidon5 } from 'poseidon-lite'

type HashFn = (m: Uint8Array<ArrayBufferLike>) => Uint8Array<ArrayBufferLike>
type HashFn = (m: Uint8Array) => Uint8Array
// TODO: to modularize this hasher, we can add more hash functions here
function blake2BWrapper (m: Uint8Array) {
return blake2b(m, { dkLen: 64 })
Expand Down Expand Up @@ -78,4 +78,5 @@ class RFC9591Hasher {
}
}

export default RFC9591Hasher
export type { HashFn }
export { RFC9591Hasher }
100 changes: 3 additions & 97 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,98 +1,4 @@
/* eslint-disable jsdoc/require-jsdoc */
import * as pkg from './module-index.js'

import { getPublicKey } from '@noble/ed25519'
import type { Point } from '@zk-kit/baby-jubjub'
import { bigIntToBuffer, bufferToBigInt, leBigIntToBuffer, leBufferToBigInt } from '@zk-kit/utils'
import msgpack from 'msgpack-lite'

import type { Signature } from './eddsa/babyposeidon.js'
import { EddsaPoseidon, eddsaBuild } from './eddsa/index.js'
import { BabyFROST, frost } from './frost/index.js'
import { DKGManager, FROSTSigningManager } from './manager/index.js'
import { poseidonFn } from './poseidon/poseidon-lite-wrapper.js'

function poseidon (inputs: Uint8Array[]) {
const result = poseidonFn(inputs.map(a => a.reverse())) as bigint
return bigIntToBuffer(result).toReversed()
}

function poseidonHex (inputs: string[], outputHex = false) {
// TODO: sanitize inputs 32 bytes
const result = poseidon(inputs.map(BigInt).map(bigIntToBuffer))
const output = bufferToBigInt(result)
return outputHex ? output.toString(16) : output
}

function getPublicSpendingKey (privateKey: Uint8Array): [bigint, bigint] {
if (privateKey.length !== 32) throw Error('Invalid private key length')
return eddsaBuild.prv2pub(Buffer.from(privateKey))
}

async function getPublicViewingKey (privateViewingKey: Uint8Array): Promise<Uint8Array> {
return getPublicKey(privateViewingKey)
}

function signEDDSA (privateKey: Uint8Array, message: bigint): Signature {
// convert bigint to uint8array
const u8 = bigIntToBuffer(message)
return eddsaBuild.signPoseidon(Buffer.from(privateKey), u8)
}

function verifyEDDSA (message: bigint, signature: Signature, pubkey: [bigint, bigint]) {
// convert bigint to uint8array
const u8 = bigIntToBuffer(message)
return eddsaBuild.verifyPoseidon(u8, signature, pubkey)
}

function getShareableViewingKey (spendingPublicKey: Point<bigint>, viewingPrivateKey: Uint8Array) {
const spendingPublicKeyString = eddsaBuild.fromBytes(eddsaBuild.packPoint(spendingPublicKey)).toString(16).padStart(64, '0')
const data = {
vpriv: eddsaBuild.fromBytes(viewingPrivateKey.toReversed()).toString(16),
spub: spendingPublicKeyString,
}
return msgpack.encode(data).toString('hex')
}

export type * from './frost/types.js'

export type { Point }

export {
frost,
bufferToBigInt,
bigIntToBuffer,
leBigIntToBuffer,
leBufferToBigInt,
BabyFROST,
FROSTSigningManager,
DKGManager,
eddsaBuild,
EddsaPoseidon,
getPublicSpendingKey,
getPublicViewingKey,
getShareableViewingKey,
signEDDSA,
verifyEDDSA,
poseidon,
poseidonHex
}

export default {
bufferToBigInt,
bigIntToBuffer,
leBigIntToBuffer,
leBufferToBigInt,
frost,
BabyFROST,
FROSTSigningManager,
DKGManager,
eddsaBuild,
EddsaPoseidon,
getPublicSpendingKey,
getPublicViewingKey,
getShareableViewingKey,
signEDDSA,
verifyEDDSA,
poseidon,
poseidonHex,
}
export * from './module-index.js'
export default pkg
4 changes: 2 additions & 2 deletions src/manager/dkg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { randomBytes } from '@noble/hashes/utils.js'
import type { Point } from '@zk-kit/baby-jubjub'
import { bufferToBigInt } from '@zk-kit/utils'

import TrustedDKG from '../frost/trusted-dkg.js'
import { TrustedDKG } from '../frost/trusted-dkg.js'
import type { EncryptedShare } from '../frost/types.js'

// Lightweight internal state to prevent wrong-order usage and surface clear errors
Expand Down Expand Up @@ -275,4 +275,4 @@ class DKGManager {
}
}

export default DKGManager
export { DKGManager, DKGFlowState }
5 changes: 2 additions & 3 deletions src/manager/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
import DKGManager from './dkg.js'
import FROSTSigningManager from './signing.js'
export { FROSTSigningManager, DKGManager }
export * from './dkg.js'
export * from './signing.js'
4 changes: 2 additions & 2 deletions src/manager/signing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ type SigningSession = {
remoteSigners: Commitment[],
partials: bigint[]
}

/* eslint-disable jsdoc/require-jsdoc */
class FROSTSigningManager {
frost: BabyFROST
Expand Down Expand Up @@ -192,4 +191,5 @@ class FROSTSigningManager {
}
}

export default FROSTSigningManager
export type { SignerShare, SessionBinding, PartialSignature, SigningSession }
export { FROSTSigningManager }
117 changes: 117 additions & 0 deletions src/module-index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/* eslint-disable jsdoc/require-jsdoc */

import { getPublicKey } from '@noble/ed25519'
import type { Point } from '@zk-kit/baby-jubjub'
import { bigIntToBuffer, bufferToBigInt, leBigIntToBuffer, leBufferToBigInt } from '@zk-kit/utils'
import msgpack from 'msgpack-lite'

import type { Signature } from './eddsa/babyposeidon.js'
import { EddsaPoseidon, eddsaBuild } from './eddsa/index.js'
import { BabyFROST, frost } from './frost/index.js'
import { DKGManager, FROSTSigningManager } from './manager/index.js'
import { poseidonFn } from './poseidon/poseidon-lite-wrapper.js'

function poseidon (inputs: Uint8Array[]) {
const result = poseidonFn(inputs.map(a => a.reverse())) as bigint
return bigIntToBuffer(result).toReversed()
}

function poseidonHex (inputs: string[], outputHex = false) {
// TODO: sanitize inputs 32 bytes
const result = poseidon(inputs.map(BigInt).map(bigIntToBuffer))
const output = bufferToBigInt(result)
return outputHex ? output.toString(16) : output
}

function getPublicSpendingKey (privateKey: Uint8Array): [bigint, bigint] {
if (privateKey.length !== 32) throw Error('Invalid private key length')
return eddsaBuild.prv2pub(Buffer.from(privateKey))
}

async function getPublicViewingKey (privateViewingKey: Uint8Array): Promise<Uint8Array> {
return getPublicKey(privateViewingKey)
}

function signEDDSA (privateKey: Uint8Array, message: bigint): Signature {
// convert bigint to uint8array
const u8 = bigIntToBuffer(message)
return eddsaBuild.signPoseidon(Buffer.from(privateKey), u8)
}

function verifyEDDSA (message: bigint, signature: Signature, pubkey: [bigint, bigint]) {
// convert bigint to uint8array
const u8 = bigIntToBuffer(message)
return eddsaBuild.verifyPoseidon(u8, signature, pubkey)
}

function getShareableViewingKey (spendingPublicKey: Point<bigint>, viewingPrivateKey: Uint8Array) {
const spendingPublicKeyString = eddsaBuild.fromBytes(eddsaBuild.packPoint(spendingPublicKey)).toString(16).padStart(64, '0')
const data = {
vpriv: eddsaBuild.fromBytes(viewingPrivateKey.toReversed()).toString(16),
spub: spendingPublicKeyString,
}
return msgpack.encode(data).toString('hex')
}

function decodeShareableKey (shareableKey: string) {
const buf = Buffer.from(shareableKey, 'hex')
return msgpack.decode(buf)
}

function decodeMultisigKey (multisigShareableKey: string) {
const decoded = decodeShareableKey(multisigShareableKey)

const spub = eddsaBuild.toBytes(BigInt('0x' + decoded.spub))

// const vpriv = eddsaBuild.toBytes(BigInt('0x' + decoded.vpriv))

const reformatted = {
...decoded,
vpriv: new Uint8Array(Buffer.from(decoded.vpriv, 'hex')),
spub: eddsaBuild.unpackPoint(spub),
sk: '0x' + decoded.sk,
}
return reformatted
}

function getShareableMultisigKey (spendingPublicKey: Point<bigint>, viewingPrivateKey: Uint8Array, sessionID: string, symmetricKey: string, participantId: number) {
const spendingPublicKeyString = eddsaBuild.fromBytes(eddsaBuild.packPoint(spendingPublicKey)).toString(16).padStart(64, '0')
// const sessionIdHex = Buffer.from(sessionID, 'utf-8').toString('hex')
const formattedSymmetricKey = symmetricKey.startsWith('0x') ? symmetricKey.slice(2) : symmetricKey
// const formattedParticipantId = BigInt(participantId).toString(16)
const data = {
vpriv: eddsaBuild.fromBytes(viewingPrivateKey.toReversed()).toString(16),
spub: spendingPublicKeyString,
sid: sessionID,
sk: formattedSymmetricKey,
pid: participantId
}
return msgpack.encode(data).toString('hex')
}

export type * from './frost/types.js'

export type { Point }

export {
bufferToBigInt,
bigIntToBuffer,
leBigIntToBuffer,
leBufferToBigInt,
frost,
BabyFROST,
FROSTSigningManager,
DKGManager,
eddsaBuild,
EddsaPoseidon,
getPublicSpendingKey,
getPublicViewingKey,
getShareableViewingKey,
getShareableMultisigKey,
decodeShareableKey,
decodeMultisigKey,
signEDDSA,
verifyEDDSA,
poseidon,
poseidonHex,
}
4 changes: 2 additions & 2 deletions test/dkg-manager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
import assert from 'node:assert'

import { describe, it } from 'node:test'
import DKGManager from '../src/manager/dkg'
import FROSTSigningManager from '../src/manager/signing'
import { DKGManager } from '../src/manager/dkg'
import { FROSTSigningManager } from '../src/manager/signing'
import { eddsaBuild, type Point } from '../src'
import { bigIntToBuffer } from '@zk-kit/utils'

Expand Down
Loading