grapevine-sonobe/circom/grapevine.circom
circom/grapevine.circomRaw
1pragma circom 2.1.6;
2
3include "node_modules/circomlib/circuits/poseidon.circom";
4include "node_modules/circomlib/circuits/mux1.circom";
5include "node_modules/circomlib/circuits/comparators.circom";
6include "node_modules/circomlib/circuits/gates.circom";
7include "./templates/chaff.circom";
8
9template grapevine(num_felts) {
10
11 // in_out schema
12 // 0: degrees of separation
13 // 1: secret hash from previous step
14 // 2: hash of username + secret hash from previous step
15 // 3: chaff
16
17 signal input ivc_input[4];
18 signal output ivc_output[4];
19
20 // external inputs at each folding step
21 signal input external_inputs[num_felts+2+2];
22 signal phrase[num_felts]; // secret phrase, if first iteration
23 for (var i=0; i<num_felts; i++) {
24 phrase[i] <== external_inputs[i];
25 }
26 signal usernames[2]; // prev username, current username
27 usernames[0]<==external_inputs[num_felts];
28 usernames[1]<==external_inputs[num_felts+1];
29 signal auth_secrets[2]; // prev degree's user secret, current degree's user secret
30 auth_secrets[0]<==external_inputs[num_felts+2];
31 auth_secrets[1]<==external_inputs[num_felts+3];
32
33 // name inputs from step_in
34 signal degrees_of_separation <== ivc_input[0];
35 signal given_phrase_hash <== ivc_input[1];
36 signal given_degree_secret_hash <== ivc_input[2];
37 signal is_chaff_step <== ivc_input[3];
38
39 // determine whether degrees of separation from secret is zero
40 component is_degree_zero = IsZero();
41 is_degree_zero.in <== degrees_of_separation;
42
43 // compute poseidon hash of secret
44 // same as the word essentially
45 component phrase_hasher = Poseidon(num_felts);
46 phrase_hasher.inputs <== phrase;
47
48 // mux between computed hash and previous iteration's hash to get phrase hash to use
49 // if degrees of separation = 0 use computed hash, else use hash from previous step
50 component phrase_mux = Mux1();
51 phrase_mux.c[0] <== given_phrase_hash;
52 phrase_mux.c[1] <== phrase_hasher.out;
53 phrase_mux.s <== is_degree_zero.out;
54
55 // compute hash of given degree secret
56 // H(H(preimage), username, auth_secret[0])
57 // where preimage is muxed depending on whether degree N is 1 or > 1
58 component degree_secret_hasher = Poseidon(3);
59 degree_secret_hasher.inputs[0] <== phrase_mux.out;
60 degree_secret_hasher.inputs[1] <== usernames[0];
61 degree_secret_hasher.inputs[2] <== auth_secrets[0];
62
63 // compare computed degree secret hash to prev degree secret hash
64 component degree_secret_hash_match = IsEqual();
65 degree_secret_hash_match.in[0] <== degree_secret_hasher.out;
66 degree_secret_hash_match.in[1] <== given_degree_secret_hash;
67
68 // create boolean that is true if either is true:
69 // - given degree secret hash matches computed hash
70 // - is a chaff step
71 component degree_secret_match_or_chaff = OR();
72 degree_secret_match_or_chaff.a <== degree_secret_hash_match.out;
73 degree_secret_match_or_chaff.b <== is_chaff_step;
74
75 // create boolean that is muxes according to:
76 // - if degrees of separation = 0, always true (no check needed)
77 // - if degree of separation > 0, return output of degree_secret_match_or_chaff
78 component degree_secret_satisfied_mux = Mux1();
79 degree_secret_satisfied_mux.c[0] <== degree_secret_match_or_chaff.out;
80 degree_secret_satisfied_mux.c[1] <== 1;
81 degree_secret_satisfied_mux.s <== is_degree_zero.out;
82
83 // constrain degree_secret_satisfied_mux to be true
84 degree_secret_satisfied_mux.out === 1;
85
86 // compute the next username hash
87 component next_degree_secret_hash = Poseidon(3);
88 next_degree_secret_hash.inputs[0] <== phrase_mux.out;
89 next_degree_secret_hash.inputs[1] <== usernames[1];
90 next_degree_secret_hash.inputs[2] <== auth_secrets[1];
91
92 // mux step_out signal according to whether or not this is a chaff step
93 component chaff_mux = ChaffMux();
94 chaff_mux.degrees_of_separation <== degrees_of_separation;
95 chaff_mux.given_phrase_hash <== given_phrase_hash;
96 chaff_mux.given_degree_secret_hash <== given_degree_secret_hash;
97 chaff_mux.is_chaff_step <== is_chaff_step;
98 chaff_mux.computed_phrase_hash <== phrase_mux.out;
99 chaff_mux.computed_degree_secret_hash <== next_degree_secret_hash.out;
100
101 // wire output signals
102 ivc_output <== chaff_mux.out;
103}
104
105component main { public [ivc_input] } = grapevine(6);