1+ import { Experimental , Field , JsonProof , MerkleTree , Poseidon , verify } from "snarkyjs" ;
2+ import ProvePasswordInTreeProgram , { PASSWORD_TREE_HEIGHT , PasswordTreePublicInput , PasswordTreeWitness } from "../zkPrograms/passwordTreeProof" ;
3+ import { PluginType } from "../plugin" ;
4+
5+ const PasswordInTreeProofClass = Experimental . ZkProgram . Proof ( ProvePasswordInTreeProgram ) ;
6+
7+ abstract class TreeStorage {
8+ abstract getRoot ( ) : Promise < Field > ;
9+ abstract getWitness ( uid : bigint ) : Promise < undefined | PasswordTreeWitness > ;
10+ abstract getRole ( uid : bigint ) : Promise < undefined | string > ;
11+ }
12+
13+ class InMemoryStorage implements TreeStorage {
14+ roles : Map < bigint , string > ;
15+ merkleTree : MerkleTree ;
16+
17+ constructor ( roleMappings : Array < [ bigint , Field , string ] > = [ ] ) {
18+ this . roles = new Map ( ) ;
19+ this . merkleTree = new MerkleTree ( PASSWORD_TREE_HEIGHT ) ;
20+
21+ roleMappings . forEach ( ( [ uid , password , role ] ) => {
22+ this . roles . set ( uid , role ) ;
23+ this . merkleTree . setLeaf ( uid , Poseidon . hash ( [ password ] ) ) ;
24+ } )
25+ }
26+
27+ async getRoot ( ) { return this . merkleTree . getRoot ( ) ; }
28+
29+ async getWitness ( uid : bigint ) {
30+ if ( ! this . roles . has ( uid ) ) return undefined ;
31+ return new PasswordTreeWitness ( this . merkleTree . getWitness ( uid ) )
32+ }
33+
34+ async getRole ( uid : bigint ) { return this . roles . get ( uid ) ; }
35+ }
36+
37+ const storage = new InMemoryStorage ( [
38+ [ BigInt ( 0 ) , Field ( '7555220006856562833147743033256142154591945963958408607501861037584894828141' ) , 'admin' ] ,
39+ [ BigInt ( 1 ) , Field ( '21565680844461314807147611702860246336805372493508489110556896454939225549736' ) , 'member' ]
40+ ] ) ;
41+
42+ const compile = async ( ) : Promise < string > => {
43+ console . log ( 'Compiling SimplePasswordTree program' ) ;
44+ console . log ( ProvePasswordInTreeProgram ) ;
45+ const { verificationKey } = await ProvePasswordInTreeProgram . compile ( ) ;
46+ return verificationKey ;
47+ }
48+
49+ const verifyAndGetRoleProgram = async (
50+ jsonProof : JsonProof ,
51+ verificationKey : string ,
52+ ) : Promise < [ string | boolean | undefined , string ] > => {
53+ if ( ! verify ( jsonProof , verificationKey ) ) {
54+ return [ false , 'proof invalid' ] ;
55+ }
56+ const proof = PasswordInTreeProofClass . fromJSON ( jsonProof ) ;
57+ const role = await storage . getRole ( proof . publicInput . witness . calculateIndex ( ) . toBigInt ( ) ) ;
58+ if ( ! role ) { return [ undefined , 'unknown public input' ] ; }
59+ return [ role , 'role proved' ] ;
60+ }
61+
62+ async function fetchPublicInput ( uid : bigint ) : Promise < undefined | PasswordTreePublicInput > {
63+ const root = await storage . getRoot ( ) ;
64+ const witness = await storage . getWitness ( uid ) ;
65+ if ( ! witness ) return undefined ;
66+ return new PasswordTreePublicInput ( { root, witness } ) ;
67+ }
68+
69+ const prove = async ( inputs : string [ ] ) : Promise < undefined | JsonProof > => {
70+ const [ uidStr , secretInput ] = inputs ;
71+ const uid : bigint = BigInt ( uidStr ) ;
72+ const publicInput = await fetchPublicInput ( uid ) ;
73+ if ( ! publicInput ) return undefined ;
74+ const proof = await ProvePasswordInTreeProgram . baseCase (
75+ publicInput , Field ( secretInput ) ) ;
76+ return proof . toJSON ( ) ;
77+ }
78+
79+ // FIXME: I have no idea what this should do
80+ const getInputs = async ( ) : Promise < string [ ] > => {
81+ return Array . from ( storage . roles . keys ( ) ) . map ( k => k . toString ( ) ) ;
82+ } ;
83+
84+ export const SimplePasswordTree : PluginType = {
85+ compile,
86+ getInputs,
87+ verify : verifyAndGetRoleProgram ,
88+ prove,
89+ }
90+
91+ export default SimplePasswordTree ;
0 commit comments