Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ZK circuits for OpenID Authenticator #583

Closed
wants to merge 33 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
ffa6754
Commit all circuit-related code
mskd12 May 4, 2023
20b6bc6
Minor
mskd12 May 5, 2023
cf0a323
Add browser bench
mskd12 May 5, 2023
4eb1009
Add script to generate user address
mskd12 May 5, 2023
c05fbed
Minor tweaks
mskd12 May 9, 2023
8a89f83
Fix range check. Make JS API cleaner to allow user inputs.
mskd12 May 9, 2023
f02eb54
Implement Nonce checks
mskd12 May 10, 2023
cb840f9
Add preamble to nonce. Use one circuit for all providers
mskd12 May 11, 2023
7b4c900
Remove redundant JS bench (present in deepak/openid-bench). Make js/p…
mskd12 May 11, 2023
63030d1
Fix README
mskd12 May 11, 2023
1e89a28
Generalize key claim checks
mskd12 May 16, 2023
006c8cc
Add comments for readability. Make npm run prove work
mskd12 May 17, 2023
2a70443
Update README
mskd12 May 17, 2023
1f549c0
gitignore + readme update
joyqvq May 17, 2023
ad4c74f
Simplify
mskd12 May 17, 2023
7fb2a21
Minor change to GTBitvector
mskd12 May 18, 2023
d3b95f0
Add circuit, wasm, sample inputs for benchmarks
mskd12 May 18, 2023
23404d1
Remove wasm
mskd12 May 18, 2023
6145245
Fix LTBitVector corner case
mskd12 May 19, 2023
34dfecb
Add a todo test
mskd12 May 19, 2023
c6e10a8
Slice -> SliceGrouped
mskd12 May 22, 2023
ed0f813
Improve cli args for prove.js
mskd12 May 23, 2023
a4d2af5
v0.1 for deployment testing
mskd12 May 25, 2023
04308bc
Polish zkinputs API
mskd12 May 25, 2023
37e5865
Add notes on how to invoke the back-end service
mskd12 May 25, 2023
dccaae0
Improved instructions
mskd12 May 25, 2023
03ac343
Move all JS files to TS. Tests still in JS. Most tests work except a few
mskd12 May 25, 2023
bbd602e
Add poseidon-lite tests
mskd12 May 31, 2023
82e1b43
Merge with deepak/openid-circuits
mskd12 Jun 6, 2023
8fa0405
1. Update snarkjs to latest
mskd12 Jun 7, 2023
ae9e10e
Rename folder
mskd12 Jun 7, 2023
baf15ec
Refactor README. Make backend accessing instructions clear
mskd12 Jun 7, 2023
f36540e
(WIP) Robust key-value pair parsing
mskd12 Jun 8, 2023
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
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,9 @@ fastcrypto/Cargo.lock
fastcrypto-derive/Cargo.lock

# .DS_Store files
.DS_Store
.DS_Store

# JS
node_modules/

fastcrypto/openid-zkp-auth/artifacts/
82 changes: 82 additions & 0 deletions zklogin-circuits/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# zkLogin circuits

Install via `tsc` and `npm install`

## Filetree Description

```bash
circuits/
zklogin.circom # Main circuit code
zklogin_wrapper.circom # Circom runner
helpers/
base64.circom
hasher.circom
jwtchecks.circom
misc.circom
sha256.circom
strings.circom
src/
circuitutils.ts # Circuit utilities
constants.ts # Circuit params
decideparams.ts # A script to decide circuit params based on real JWTs
jwtutils.ts # JWT utilities
prove.ts # Helper script to run the ZKP using a given zkey, vkey, JWT
utils.ts # Generic utilities
verify.ts
test/
testutils.js # Test utilities
xyz.circom.test.js # testing circom code
abc.test.js # testing js code
testvectors/
realJWTs.ts # Real JWTs
sampleWalletInputs.json
sampleZKPInputs.json
```

## Steps to generate a OpenID signature (using snarkJS prover)

1. Create a folder named `artifacts` inside `openid-zkp-auth`.

```
cd fastcrypto/openid-zkp-auth && mkdir artifacts
```

2. Get pre-generated trusted setup and place it inside `artifacts`.

```
cd artifacts && wget https://hermez.s3-eu-west-1.amazonaws.com/powersOfTau28_hez_final_20.ptau
```

3. Generate R1CS and witness generator (WASM):

```
cd ../ && circom circuits/zklogin.circom --r1cs --wasm --output artifacts

# maybe need
npm install
```

4. Run circuit-specific trusted setup: `cd artifacts && snarkjs groth16 setup zklogin.r1cs powersOfTau28_hez_final_20.ptau zklogin.zkey`

5. Export verification key: `snarkjs zkey export verificationkey zklogin.zkey zklogin.vkey`

6. Create a folder named `proof` inside the `artifacts` directory. Generate a OpenID signature: ``npm run prove <provider> <jwt>``. The last two arguments are optional. `provider` can be either `google` (default) or `twitch`. Default JWTs for both are in `testvectors/realJWTs.js`.

It generates three files: the zk proof (`zkp.proof`), auxiliary inputs to the verifier (`aux.json`) and public inputs to the ZKP (`public.json`) inside the `proof` folder.

## Tests

``tsc; npm test``

# Steps to access the back-end

The back-end takes `WalletInputs` as input and returns `PartialZKLoginSig`. Both these structs are defined in `src/common.ts`.

## Example via cURL

```
1. cd testvectors
2. curl -X POST -H "Content-Type: application/json" -d @./sampleWalletInputs.json http://185.209.177.123:8000/zkp
```

Note that the command reads the `WalletInputs` from the JSON file `testvectors/sampleWalletInputs.json`.
144 changes: 144 additions & 0 deletions zklogin-circuits/circuits/helpers/base64.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
pragma circom 2.1.3;

include "misc.circom";

function asciiToBase64Url(i) {
var base64 = 0;
if (i >= 65 && i <= 90) { // A to Z
base64 = i - 65;
} else if (i >= 97 && i <= 122) { // a to z
base64 = i - 71;
} else if (i >= 48 && i <= 57) { // 0 to 9
base64 = i + 4;
} else if (i == 45) { // -
base64 = 62;
} else if (i == 95) { // _
base64 = 63;
}
return base64;
}

/**
Takes as input a base64url character and outputs the corresponding 6-bit value.
If not a valid base64 character, outputs 0.

Cost: 73 constraints

- in: The base64url character. Assumed to be a 8-bit number, i.e., in [0, 256)
NOTE: Behavior is undefined otherwise.
- out: The 6-bit value
*/
template Base64URLToBits() {
signal input in;
signal output out[6];

// Compute the base64 representation of in, e.g., if in = 66 ('B') then outascii = 1
// This step does not add any constraints.
// We check the correctness of the base64 representation next.
signal outascii;
outascii <-- asciiToBase64Url(in);

component lt91;
lt91 = LessThan(8);
lt91.in[0] <== in;
lt91.in[1] <== 91;

component gt64;
gt64 = GreaterThan(8);
gt64.in[0] <== in;
gt64.in[1] <== 64;

// If in is in [65, 90], then outascii = in - 65 (line 8 of asciiToBase64Url)
component forceequal1;
forceequal1 = MyForceEqualIfEnabled();
forceequal1.enabled <== lt91.out * gt64.out;
forceequal1.in[0] <== outascii;
forceequal1.in[1] <== in - 65;

component lt123;
lt123 = LessThan(8);
lt123.in[0] <== in;
lt123.in[1] <== 123;

component gt96;
gt96 = GreaterThan(8);
gt96.in[0] <== in;
gt96.in[1] <== 96;

// If in is in [97, 122], then outascii = in - 71 (line 10 of asciiToBase64Url)
component forceequal2;
forceequal2 = MyForceEqualIfEnabled();
forceequal2.enabled <== lt123.out * gt96.out;
forceequal2.in[0] <== outascii;
forceequal2.in[1] <== in - 71;

component lt58;
lt58 = LessThan(8);
lt58.in[0] <== in;
lt58.in[1] <== 58;

component gt47;
gt47 = GreaterThan(8);
gt47.in[0] <== in;
gt47.in[1] <== 47;

// If in is in [48, 57], then outascii = in + 4 (line 12 of asciiToBase64Url)
component forceequal3;
forceequal3 = MyForceEqualIfEnabled();
forceequal3.enabled <== lt58.out * gt47.out;
forceequal3.in[0] <== outascii;
forceequal3.in[1] <== in + 4;

component eq45;
eq45 = IsEqual();
eq45.in[0] <== in;
eq45.in[1] <== 45;

// If in is 45, then outascii = 62 (line 14 of asciiToBase64Url)
component forceequal4;
forceequal4 = MyForceEqualIfEnabled();
forceequal4.enabled <== eq45.out;
forceequal4.in[0] <== outascii;
forceequal4.in[1] <== 62;

component eq95;
eq95 = IsEqual();
eq95.in[0] <== in;
eq95.in[1] <== 95;

// If in is 95, then outascii = 63 (line 16 of asciiToBase64Url)
component forceequal5;
forceequal5 = MyForceEqualIfEnabled();
forceequal5.enabled <== eq95.out;
forceequal5.in[0] <== outascii;
forceequal5.in[1] <== 63;

// Note: any = 0 happens only if all the enabled signals are 0.
// This is because all the enabled signals are guaranteed to be either 0 or 1.
var any = 1 - (forceequal1.enabled + forceequal2.enabled + forceequal3.enabled + forceequal4.enabled + forceequal5.enabled);

// If in is not a valid base64url character, then outascii = 0
component forceequal6;
forceequal6 = MyForceEqualIfEnabled();
forceequal6.enabled <== any;
forceequal6.in[0] <== outascii;
forceequal6.in[1] <== 0;

component convert = Num2BitsBE(6);
convert.in <== outascii;
for (var i = 0; i < 6; i++) {
out[i] <== convert.out[i];
}
}

template MultiBase64URLToBits(n) {
signal input in[n];
signal output out[n * 6];

for (var i = 0; i < n; i++) {
var bits[6] = Base64URLToBits()(in[i]);
for (var j = 0; j < 6; j++) {
out[i * 6 + j] <== bits[j];
}
}
}
33 changes: 33 additions & 0 deletions zklogin-circuits/circuits/helpers/hasher.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
pragma circom 2.1.3;

include "../../node_modules/circomlib/circuits/poseidon.circom";

template Hasher(nInputs) {
signal input in[nInputs];
signal output out;

component pos1, pos2;
// See https://github.com/iden3/circomlib/blob/master/circuits/poseidon.circom#L78.
// It implicitly forces t <= 17 or nInputs <= 16.
// TODO: The current limitation of 15 comes from the rust library we use (https://github.com/Lightprotocol/light-poseidon).
if (nInputs <= 15) {
out <== Poseidon(nInputs)(in);
} else if (nInputs <= 30) {
pos1 = Poseidon(15);
pos2 = Poseidon(nInputs - 15);

for (var i = 0; i < 15; i++) {
pos1.inputs[i] <== in[i];
}
for (var i = 15; i < nInputs; i++) {
pos2.inputs[i - 15] <== in[i];
}

out <== Poseidon(2)([
pos1.out,
pos2.out
]);
} else { // Yet to be implemented
1 === 0;
}
}
Loading