11import { DisplayOptions , PCDPackage , SerializedPCD } from "@pcd/pcd-types" ;
22import { fromHexString , requireDefinedParameter , toHexString } from "@pcd/util" ;
3- import { Eddsa , Point , buildEddsa } from "circomlibjs" ;
3+ import {
4+ derivePublicKey ,
5+ packSignature ,
6+ signMessage ,
7+ unpackSignature ,
8+ verifySignature
9+ } from "@zk-kit/eddsa-poseidon" ;
10+ import { poseidon1 } from "poseidon-lite/poseidon1" ;
11+ import { poseidon12 } from "poseidon-lite/poseidon12" ;
12+ import { poseidon13 } from "poseidon-lite/poseidon13" ;
13+ import { poseidon2 } from "poseidon-lite/poseidon2" ;
14+ import { poseidon3 } from "poseidon-lite/poseidon3" ;
415import { v4 as uuid } from "uuid" ;
516import {
617 EdDSAInitArgs ,
@@ -12,31 +23,11 @@ import {
1223 EdDSAPublicKey
1324} from "./EdDSAPCD" ;
1425
15- let initializedPromise : Promise < void > | undefined ;
16- let eddsa : Eddsa ;
17-
18- /**
19- * A promise designed to make sure that the EdDSA algorithm
20- * of the `circomlibjs` package has been properly initialized.
21- * It only initializes them once.
22- */
23- async function ensureInitialized ( ) : Promise < void > {
24- if ( ! initializedPromise ) {
25- initializedPromise = ( async ( ) : Promise < void > => {
26- eddsa = await buildEddsa ( ) ;
27- } ) ( ) ;
28- }
29-
30- await initializedPromise ;
31- }
32-
3326/**
3427 * Creates a new {@link EdDSAPCD} by generating an {@link EdDSAPCDProof}
3528 * and deriving an {@link EdDSAPCDClaim} from the given {@link EdDSAPCDArgs}.
3629 */
3730export async function prove ( args : EdDSAPCDArgs ) : Promise < EdDSAPCD > {
38- await ensureInitialized ( ) ;
39-
4031 let message ;
4132
4233 if ( ! args . privateKey . value ) throw new Error ( "No private key value provided" ) ;
@@ -60,16 +51,12 @@ export async function prove(args: EdDSAPCDArgs): Promise<EdDSAPCD> {
6051 const id = typeof args . id . value === "string" ? args . id . value : uuid ( ) ;
6152 const prvKey = fromHexString ( args . privateKey . value ) ;
6253
63- const hashedMessage = eddsa . poseidon ( message ) ;
54+ const hashedMessage = poseidonHashMessage ( message ) ;
6455 const publicKey = await getEdDSAPublicKey ( prvKey ) ;
6556
6657 // Make the signature on the message.
67- // Note: packSignature converts the R8 coordinates from Mongtomery form to
68- // standard form for use outside of circomlibjs.
69- // This is a reference to Montgomery form of numbers for modular
70- // multiplication, NOT Montgomery form of eliptic curves. See https://en.wikipedia.org/wiki/Montgomery_modular_multiplication#Montgomery_form
7158 const signature = toHexString (
72- eddsa . packSignature ( eddsa . signPoseidon ( prvKey , hashedMessage ) )
59+ packSignature ( signMessage ( prvKey , hashedMessage ) )
7360 ) ;
7461
7562 return new EdDSAPCD ( id , { message, publicKey } , { signature } ) ;
@@ -81,22 +68,20 @@ export async function prove(args: EdDSAPCDArgs): Promise<EdDSAPCD> {
8168 */
8269export async function verify ( pcd : EdDSAPCD ) : Promise < boolean > {
8370 try {
84- await ensureInitialized ( ) ;
85-
86- const signature = eddsa . unpackSignature ( fromHexString ( pcd . proof . signature ) ) ;
71+ const signature = unpackSignature ( fromHexString ( pcd . proof . signature ) ) ;
8772
8873 // Note: `F.fromObject` converts a coordinate from standard format to
8974 // Montgomery form, which is expected by circomlibjs. unpackSignature above
9075 // does the same for its R8 point.
9176 // This is a reference to Montgomery form of numbers for modular
9277 // multiplication, NOT Montgomery form of eliptic curves. See https://en.wikipedia.org/wiki/Montgomery_modular_multiplication#Montgomery_form
93- const pubKey = pcd . claim . publicKey . map ( ( p ) =>
94- eddsa . F . fromObject ( p )
95- ) as Point ;
78+ const pubKey = pcd . claim . publicKey . map ( ( coordinateString : string ) =>
79+ BigInt ( "0x" + coordinateString )
80+ ) as [ bigint , bigint ] ;
9681
97- const hashedMessage = eddsa . poseidon ( pcd . claim . message ) ;
82+ const hashedMessage = poseidonHashMessage ( pcd . claim . message ) ;
9883
99- return eddsa . verifyPoseidon ( hashedMessage , signature , pubKey ) ;
84+ return verifySignature ( hashedMessage , signature , pubKey ) ;
10085 } catch {
10186 return false ;
10287 }
@@ -205,17 +190,37 @@ export const EdDSAPCDPackage: PCDPackage<
205190export async function getEdDSAPublicKey (
206191 privateKey : string | Uint8Array
207192) : Promise < EdDSAPublicKey > {
208- await ensureInitialized ( ) ;
209-
210193 if ( typeof privateKey === "string" ) {
211194 privateKey = fromHexString ( privateKey ) ;
212195 }
213196
214- return eddsa . prv2pub ( privateKey ) . map ( ( p ) =>
215- // Note: `F.toObject` converts a point from the Montgomery format used by
216- // circomlibjs to standard form.
217- // This is a reference to Montgomery form of numbers for modular
218- // multiplication, NOT Montgomery form of eliptic curves. See https://en.wikipedia.org/wiki/Montgomery_modular_multiplication#Montgomery_form
219- eddsa . F . toObject ( p ) . toString ( 16 ) . padStart ( 64 , "0" )
197+ return derivePublicKey ( privateKey ) . map ( ( coordinate : bigint ) =>
198+ coordinate . toString ( 16 ) . padStart ( 64 , "0" )
220199 ) as EdDSAPublicKey ;
221200}
201+
202+ function poseidonHashMessage ( message : bigint [ ] ) : bigint {
203+ switch ( message . length ) {
204+ case 1 :
205+ // Used by PODs for value hashing, so no extra bundle size impact.
206+ return poseidon1 ( message ) ;
207+ case 2 :
208+ // Used by PODs for Merkle tree hasing, so no extra bundle size impact.
209+ return poseidon2 ( message ) ;
210+ case 3 :
211+ // Used by unit tests, including backward-compatibility with fixed values.
212+ // Used by GPCs for tuple hasing, so no extra bundle size impact.
213+ return poseidon3 ( message ) ;
214+ case 12 :
215+ // Tailored to the size of EdDSATicketPCD.
216+ return poseidon12 ( message ) ;
217+ case 13 :
218+ // Tailored to the size of EdDSAFrogPCD.
219+ return poseidon13 ( message ) ;
220+ default :
221+ break ;
222+ }
223+ throw new Error (
224+ `Unsupported EdDSAMessagePCD message size ${ message . length } .`
225+ ) ;
226+ }
0 commit comments