Skip to content

Commit

Permalink
fix: update verifier interface and address gen (#13124)
Browse files Browse the repository at this point in the history
## Description 
this PR contains mainly 3 changes: 
1. update to use the new entrypoint in fastcrypto: verify_zklogin
2. update JWK updater to use fetch_jwks in fastcrypto and store the
(kid, iss) -> jwk mapping, instead of kid -> jwk. so we can support
multiple iss (providers). this also lets fastcrypto manage "supported
providers". few renaming from OAuthProviderContent to JWK.
3. protocol config change: zklogin_supported_providers, use_secure_vk.
zklogin_auth flag still in place this is only enabled for devnet.

(4 for testing) keytool command for e2e testing

based on MystenLabs/fastcrypto#615

## Test Plan 
```
# start a localnet
cargo run --bin sui-test-validator

# in another tab
cargo build --bin sui && target/debug/sui keytool zk-login-sign-and-execute-tx --max-epoch 10 --fixed true

# use prompt to test 3 providers' url, use fixed if you want the default key and randomness

Ephemeral key identifier: 0xcc2196ee1fa156836daf9bb021d88d648a0023fa387e695d3701667a634a331f
Ephemeral pubkey (BigInt): 84029355920633174015103288781128426107680789454168570548782290541079926444544
Jwt randomness: 100681567828351849884072155819400689117
Visit URL (Google): https://accounts.google.com/o/oauth2/v2/auth?client_id=575519204237-msop9ep45u2uo98hapqmngv8d84qdc8k.apps.googleusercontent.com&response_type=id_token&redirect_uri=https://sui.io/&scope=openid&nonce=hTPpgF7XAKbW37rEUS6pEVZqmoI
Visit URL (Twitch): https://id.twitch.tv/oauth2/authorize?client_id=rs1bh065i9ya4ydvifixl4kss0uhpt&force_verify=true&lang=en&login_type=login&redirect_uri=https://sui.io/&response_type=id_token&scope=openid&nonce=hTPpgF7XAKbW37rEUS6pEVZqmoI
Visit URL (Facebook): https://www.facebook.com/v17.0/dialog/oauth?client_id=233307156352917&redirect_uri=https://sui.io/&scope=openid&nonce=hTPpgF7XAKbW37rEUS6pEVZqmoI&response_type=id_token
Finish login and paste the entire URL here (e.g. https://sui.io/#id_token=...):
https://sui.io/#id_token=$YOUR_TOKEN_HERE&authuser=1&prompt=none
User salt: 37603297217831327253368351620768767386
ZkLogin inputs:
"{\"proof_points\":{\"pi_a\":[\"11919750190958936097341971645310122361427237718339506968604484178434524183763\",\"4066396655503961643966719205021673883457905225199432791695293704762383515464\",\"1\"],\"pi_b\":[[\"4944611897670024879056817717532675736403113855465546218202719469807483285716\",\"16588919619512150925750036824511259013041883375734888504590662076356111031305\"],[\"21216051686412759119183634053470555744351991062479561416927343692238334485548\",\"7497144533451348825947902642248234141372654747858237668577407146943851844730\"],[\"1\",\"0\"]],\"pi_c\":[\"14631487662109801464392056573524864320058039577512853397500854951219322772917\",\"17171172537255313036364669593310031389402112944054741144631323570508702243961\",\"1\"]},\"address_seed\":\"6766845480040838487230155646516397460223616307094485793506729789519059777352\",\"claims\":[{\"name\":\"iss\",\"value_base64\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"index_mod_4\":1},{\"name\":\"aud\",\"value_base64\":\"CJhdWQiOiI1NzU1MTkyMDQyMzctbXNvcDllcDQ1dTJ1bzk4aGFwcW1uZ3Y4ZDg0cWRjOGsuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLC\",\"index_mod_4\":1}],\"header_base64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjdjOWM3OGUzYjAwZTFiYjA5MmQyNDZjODg3YjExMjIwYzg3YjdkMjAiLCJ0eXAiOiJKV1QifQ\"}"
ZkLogin Address: 0x504aade5d02308b1b7e58775adde9e1316f71898e2996c94ddd668fd559cdf32
Faucet requested and created test transaction: V1(TransactionDataV1 { kind: ProgrammableTransaction(ProgrammableTransaction { inputs: [Pure([190, 243, 14, 103, 26, 137, 73, 150, 28, 21, 83, 14, 186, 35, 123, 183, 214, 96, 104, 37, 174, 31, 244, 109, 131, 136, 4, 129, 106, 24, 197, 127]), Object(ImmOrOwnedObject((0xd93388f0bcdd1730ee4d5ff3b73a2f5301a2f6e13df3b84d23155698a9b450c6, SequenceNumber(2), o#FFJqkV96f6VtsyGKEn2BqJokAy6oGuW3SUsYtthgrvCk)))], commands: [TransferObjects([Input(1)], Input(0))] }), sender: 0x504aade5d02308b1b7e58775adde9e1316f71898e2996c94ddd668fd559cdf32, gas_data: GasData { payment: [(0x3f34a90f021abdc7928c335da354553255b96af4f8237a7d896a98febb58ab9e, SequenceNumber(2), o#3q1NmyLmHyskTwSMG7r7rSBDUd1kkiZQULoXmDGYDH8S)], owner: 0x504aade5d02308b1b7e58775adde9e1316f71898e2996c94ddd668fd559cdf32, price: 1000, budget: 5000000 }, expiration: None })
ZkLogin Authenticator Signature Serialized: "BQNNMTE5MTk3NTAxOTA5NTg5MzYwOTczNDE5NzE2NDUzMTAxMjIzNjE0MjcyMzc3MTgzMzk1MDY5Njg2MDQ0ODQxNzg0MzQ1MjQxODM3NjNMNDA2NjM5NjY1NTUwMzk2MTY0Mzk2NjcxOTIwNTAyMTY3Mzg4MzQ1NzkwNTIyNTE5OTQzMjc5MTY5NTI5MzcwNDc2MjM4MzUxNTQ2NAExAwJMNDk0NDYxMTg5NzY3MDAyNDg3OTA1NjgxNzcxNzUzMjY3NTczNjQwMzExMzg1NTQ2NTU0NjIxODIwMjcxOTQ2OTgwNzQ4MzI4NTcxNk0xNjU4ODkxOTYxOTUxMjE1MDkyNTc1MDAzNjgyNDUxMTI1OTAxMzA0MTg4MzM3NTczNDg4ODUwNDU5MDY2MjA3NjM1NjExMTAzMTMwNQJNMjEyMTYwNTE2ODY0MTI3NTkxMTkxODM2MzQwNTM0NzA1NTU3NDQzNTE5OTEwNjI0Nzk1NjE0MTY5MjczNDM2OTIyMzgzMzQ0ODU1NDhMNzQ5NzE0NDUzMzQ1MTM0ODgyNTk0NzkwMjY0MjI0ODIzNDE0MTM3MjY1NDc0Nzg1ODIzNzY2ODU3NzQwNzE0Njk0Mzg1MTg0NDczMAIBMQEwA00xNDYzMTQ4NzY2MjEwOTgwMTQ2NDM5MjA1NjU3MzUyNDg2NDMyMDA1ODAzOTU3NzUxMjg1MzM5NzUwMDg1NDk1MTIxOTMyMjc3MjkxN00xNzE3MTE3MjUzNzI1NTMxMzAzNjM2NDY2OTU5MzMxMDAzMTM4OTQwMjExMjk0NDA1NDc0MTE0NDYzMTMyMzU3MDUwODcwMjI0Mzk2MQExTDY3NjY4NDU0ODAwNDA4Mzg0ODcyMzAxNTU2NDY1MTYzOTc0NjAyMjM2MTYzMDcwOTQ0ODU3OTM1MDY3Mjk3ODk1MTkwNTk3NzczNTICA2lzczF5SnBjM01pT2lKb2RIUndjem92TDJGalkyOTFiblJ6TG1kdmIyZHNaUzVqYjIwaUxDAQNhdWRtQ0poZFdRaU9pSTFOelUxTVRreU1EUXlNemN0YlhOdmNEbGxjRFExZFRKMWJ6azRhR0Z3Y1cxdVozWTRaRGcwY1dSak9Hc3VZWEJ3Y3k1bmIyOW5iR1YxYzJWeVkyOXVkR1Z1ZEM1amIyMGlMQwFmZXlKaGJHY2lPaUpTVXpJMU5pSXNJbXRwWkNJNklqZGpPV00zT0dVellqQXdaVEZpWWpBNU1tUXlORFpqT0RnM1lqRXhNakl3WXpnM1lqZGtNakFpTENKMGVYQWlPaUpLVjFRaWZRCgAAAAAAAABhADkEuv1BTfolleAyzVWVZC/TpCtO0wljxjTRZKfGddxxNhfZ4hRlq438Mo6e/8HnlOZ040OFN4uAzvgrfv4G4gW5xu4WMO8+cRFEpkjbBruyKE9ydM++5T/87lA8waSSAA=="
╭──────────┬────────────────────────────────────────────────╮
│ txDigest │  9V1ie4CkQ3afLtgAGKEmGQApjahkBUu7SAUFw6jRMRjJ  │
╰──────────┴────────────────────────────────────────────────╯
2023-08-15T20:42:27.650449Z  INFO sui::keytool: ╭──────────┬────────────────────────────────────────────────╮
2023-08-15T20:42:27.650509Z  INFO sui::keytool: │ txDigest │  9V1ie4CkQ3afLtgAGKEmGQApjahkBUu7SAUFw6jRMRjJ  │
2023-08-15T20:42:27.650515Z  INFO sui::keytool: ╰──────────┴────────────────────────────────────────────────╯


# the above command should work fine for google and twitch, if the above command does not work for facebook due to pasting issue, use this command instead. all the inputs should be printed from the above command.

target/debug/sui keytool zk-login-enter-token --ephemeral-key-identifier 0xcc2196ee1fa156836daf9bb021d88d648a0023fa387e695d3701667a634a331f --max-epoch 10 --jwt-randomness 100681567828351849884072155819400689117 --kp-bigint 84029355920633174015103288781128426107680789454168570548782290541079926444544 --parsed-token $JWT_TOKEN
# use prompt to test 3 providers' url, use fixed if you want the default key and randomness

Ephemeral key identifier: 0xcc2196ee1fa156836daf9bb021d88d648a0023fa387e695d3701667a634a331f
Ephemeral pubkey (BigInt): 84029355920633174015103288781128426107680789454168570548782290541079926444544
Jwt randomness: 100681567828351849884072155819400689117
Visit URL (Google): https://accounts.google.com/o/oauth2/v2/auth?client_id=575519204237-msop9ep45u2uo98hapqmngv8d84qdc8k.apps.googleusercontent.com&response_type=id_token&redirect_uri=https://sui.io/&scope=openid&nonce=hTPpgF7XAKbW37rEUS6pEVZqmoI
Visit URL (Twitch): https://id.twitch.tv/oauth2/authorize?client_id=rs1bh065i9ya4ydvifixl4kss0uhpt&force_verify=true&lang=en&login_type=login&redirect_uri=https://sui.io/&response_type=id_token&scope=openid&nonce=hTPpgF7XAKbW37rEUS6pEVZqmoI
Visit URL (Facebook): https://www.facebook.com/v17.0/dialog/oauth?client_id=233307156352917&redirect_uri=https://sui.io/&scope=openid&nonce=hTPpgF7XAKbW37rEUS6pEVZqmoI&response_type=id_token
Finish login and paste the entire URL here (e.g. https://sui.io/#id_token=...):
https://sui.io/#id_token=$YOUR_TOKEN_HERE&authuser=1&prompt=none
User salt: 37603297217831327253368351620768767386
ZkLogin inputs:
"{\"proof_points\":{\"pi_a\":[\"11919750190958936097341971645310122361427237718339506968604484178434524183763\",\"4066396655503961643966719205021673883457905225199432791695293704762383515464\",\"1\"],\"pi_b\":[[\"4944611897670024879056817717532675736403113855465546218202719469807483285716\",\"16588919619512150925750036824511259013041883375734888504590662076356111031305\"],[\"21216051686412759119183634053470555744351991062479561416927343692238334485548\",\"7497144533451348825947902642248234141372654747858237668577407146943851844730\"],[\"1\",\"0\"]],\"pi_c\":[\"14631487662109801464392056573524864320058039577512853397500854951219322772917\",\"17171172537255313036364669593310031389402112944054741144631323570508702243961\",\"1\"]},\"address_seed\":\"6766845480040838487230155646516397460223616307094485793506729789519059777352\",\"claims\":[{\"name\":\"iss\",\"value_base64\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"index_mod_4\":1},{\"name\":\"aud\",\"value_base64\":\"CJhdWQiOiI1NzU1MTkyMDQyMzctbXNvcDllcDQ1dTJ1bzk4aGFwcW1uZ3Y4ZDg0cWRjOGsuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLC\",\"index_mod_4\":1}],\"header_base64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjdjOWM3OGUzYjAwZTFiYjA5MmQyNDZjODg3YjExMjIwYzg3YjdkMjAiLCJ0eXAiOiJKV1QifQ\"}"
ZkLogin Address: 0x504aade5d02308b1b7e58775adde9e1316f71898e2996c94ddd668fd559cdf32
Faucet requested and created test transaction: V1(TransactionDataV1 { kind: ProgrammableTransaction(ProgrammableTransaction { inputs: [Pure([190, 243, 14, 103, 26, 137, 73, 150, 28, 21, 83, 14, 186, 35, 123, 183, 214, 96, 104, 37, 174, 31, 244, 109, 131, 136, 4, 129, 106, 24, 197, 127]), Object(ImmOrOwnedObject((0xd93388f0bcdd1730ee4d5ff3b73a2f5301a2f6e13df3b84d23155698a9b450c6, SequenceNumber(2), o#FFJqkV96f6VtsyGKEn2BqJokAy6oGuW3SUsYtthgrvCk)))], commands: [TransferObjects([Input(1)], Input(0))] }), sender: 0x504aade5d02308b1b7e58775adde9e1316f71898e2996c94ddd668fd559cdf32, gas_data: GasData { payment: [(0x3f34a90f021abdc7928c335da354553255b96af4f8237a7d896a98febb58ab9e, SequenceNumber(2), o#3q1NmyLmHyskTwSMG7r7rSBDUd1kkiZQULoXmDGYDH8S)], owner: 0x504aade5d02308b1b7e58775adde9e1316f71898e2996c94ddd668fd559cdf32, price: 1000, budget: 5000000 }, expiration: None })
ZkLogin Authenticator Signature Serialized: "BQNNMTE5MTk3NTAxOTA5NTg5MzYwOTczNDE5NzE2NDUzMTAxMjIzNjE0MjcyMzc3MTgzMzk1MDY5Njg2MDQ0ODQxNzg0MzQ1MjQxODM3NjNMNDA2NjM5NjY1NTUwMzk2MTY0Mzk2NjcxOTIwNTAyMTY3Mzg4MzQ1NzkwNTIyNTE5OTQzMjc5MTY5NTI5MzcwNDc2MjM4MzUxNTQ2NAExAwJMNDk0NDYxMTg5NzY3MDAyNDg3OTA1NjgxNzcxNzUzMjY3NTczNjQwMzExMzg1NTQ2NTU0NjIxODIwMjcxOTQ2OTgwNzQ4MzI4NTcxNk0xNjU4ODkxOTYxOTUxMjE1MDkyNTc1MDAzNjgyNDUxMTI1OTAxMzA0MTg4MzM3NTczNDg4ODUwNDU5MDY2MjA3NjM1NjExMTAzMTMwNQJNMjEyMTYwNTE2ODY0MTI3NTkxMTkxODM2MzQwNTM0NzA1NTU3NDQzNTE5OTEwNjI0Nzk1NjE0MTY5MjczNDM2OTIyMzgzMzQ0ODU1NDhMNzQ5NzE0NDUzMzQ1MTM0ODgyNTk0NzkwMjY0MjI0ODIzNDE0MTM3MjY1NDc0Nzg1ODIzNzY2ODU3NzQwNzE0Njk0Mzg1MTg0NDczMAIBMQEwA00xNDYzMTQ4NzY2MjEwOTgwMTQ2NDM5MjA1NjU3MzUyNDg2NDMyMDA1ODAzOTU3NzUxMjg1MzM5NzUwMDg1NDk1MTIxOTMyMjc3MjkxN00xNzE3MTE3MjUzNzI1NTMxMzAzNjM2NDY2OTU5MzMxMDAzMTM4OTQwMjExMjk0NDA1NDc0MTE0NDYzMTMyMzU3MDUwODcwMjI0Mzk2MQExTDY3NjY4NDU0ODAwNDA4Mzg0ODcyMzAxNTU2NDY1MTYzOTc0NjAyMjM2MTYzMDcwOTQ0ODU3OTM1MDY3Mjk3ODk1MTkwNTk3NzczNTICA2lzczF5SnBjM01pT2lKb2RIUndjem92TDJGalkyOTFiblJ6TG1kdmIyZHNaUzVqYjIwaUxDAQNhdWRtQ0poZFdRaU9pSTFOelUxTVRreU1EUXlNemN0YlhOdmNEbGxjRFExZFRKMWJ6azRhR0Z3Y1cxdVozWTRaRGcwY1dSak9Hc3VZWEJ3Y3k1bmIyOW5iR1YxYzJWeVkyOXVkR1Z1ZEM1amIyMGlMQwFmZXlKaGJHY2lPaUpTVXpJMU5pSXNJbXRwWkNJNklqZGpPV00zT0dVellqQXdaVEZpWWpBNU1tUXlORFpqT0RnM1lqRXhNakl3WXpnM1lqZGtNakFpTENKMGVYQWlPaUpLVjFRaWZRCgAAAAAAAABhADkEuv1BTfolleAyzVWVZC/TpCtO0wljxjTRZKfGddxxNhfZ4hRlq438Mo6e/8HnlOZ040OFN4uAzvgrfv4G4gW5xu4WMO8+cRFEpkjbBruyKE9ydM++5T/87lA8waSSAA=="
╭──────────┬────────────────────────────────────────────────╮
│ txDigest │  9V1ie4CkQ3afLtgAGKEmGQApjahkBUu7SAUFw6jRMRjJ  │
╰──────────┴────────────────────────────────────────────────╯
2023-08-15T20:42:27.650449Z  INFO sui::keytool: ╭──────────┬────────────────────────────────────────────────╮
2023-08-15T20:42:27.650509Z  INFO sui::keytool: │ txDigest │  9V1ie4CkQ3afLtgAGKEmGQApjahkBUu7SAUFw6jRMRjJ  │
2023-08-15T20:42:27.650515Z  INFO sui::keytool: ╰──────────┴────────────────────────────────────────────────╯


# the above command should work fine for google and twitch, if the above command does not work for facebook due to pasting issue, use this command instead. all the inputs should be printed from the above command.

target/debug/sui keytool zk-login-enter-token --ephemeral-key-identifier 0xcc2196ee1fa156836daf9bb021d88d648a0023fa387e695d3701667a634a331f --max-epoch 10 --jwt-randomness 100681567828351849884072155819400689117 --kp-bigint 84029355920633174015103288781128426107680789454168570548782290541079926444544 --parsed-token $JWT_TOKEN
```


https://suiexplorer.com/txblock/9V1ie4CkQ3afLtgAGKEmGQApjahkBUu7SAUFw6jRMRjJ?network=local

![image](https://github.com/MystenLabs/sui/assets/108701016/25f15c23-c242-4aa1-9223-4230e208b84e)

---
If your changes are not user-facing and not a breaking change, you can
skip the following section. Otherwise, please indicate what changed, and
then add to the Release Notes section as highlighted during the release
process.

### Type of Change (Check all that apply)

- [x] protocol change
- [ ] user-visible impact
- [ ] breaking change for a client SDKs
- [ ] breaking change for FNs (FN binary must upgrade)
- [x] breaking change for validators or node operators (must upgrade
binaries)
- [ ] breaking change for on-chain data layout
- [ ] necessitate either a data wipe or data migration

### Release notes
  • Loading branch information
joyqvq authored and damirka committed Aug 23, 2023
1 parent 9650d00 commit 78d693d
Show file tree
Hide file tree
Showing 28 changed files with 1,276 additions and 655 deletions.
18 changes: 12 additions & 6 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -413,8 +413,8 @@ move-stackless-bytecode = { path = "external-crates/move/move-prover/bytecode" }
move-symbol-pool = { path = "external-crates/move/move-symbol-pool" }
move-abstract-stack = { path = "external-crates/move/move-abstract-stack" }

fastcrypto = { git = "https://github.com/MystenLabs/fastcrypto", rev = "e5b57ef4b3b41e799954f6cac83034154e8cf33a" }
fastcrypto-zkp = { git = "https://github.com/MystenLabs/fastcrypto", rev = "e5b57ef4b3b41e799954f6cac83034154e8cf33a", package = "fastcrypto-zkp" }
fastcrypto = { git = "https://github.com/MystenLabs/fastcrypto", rev = "4e7debce78340848f0009b648f56d912d6bd02d5" }
fastcrypto-zkp = { git = "https://github.com/MystenLabs/fastcrypto", rev = "4e7debce78340848f0009b648f56d912d6bd02d5", package = "fastcrypto-zkp" }

# anemo dependencies
anemo = { git = "https://github.com/mystenlabs/anemo.git", rev = "0f0ae8d8f222820a20b586088ea7a2941478a159" }
Expand Down
3 changes: 3 additions & 0 deletions crates/sui-core/benches/batch_verification_bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use sui_types::committee::Committee;
use sui_types::crypto::{get_key_pair, AccountKeyPair, AuthorityKeyPair};
use sui_types::transaction::CertifiedTransaction;

use fastcrypto_zkp::bn254::zk_login_api::ZkLoginEnv;
use sui_core::signature_verifier::*;

fn gen_certs(
Expand Down Expand Up @@ -75,6 +76,8 @@ fn async_verifier_bench(c: &mut Criterion) {
committee.clone(),
batch_size,
metrics.clone(),
vec![],
ZkLoginEnv::Test,
));

b.iter(|| {
Expand Down
49 changes: 33 additions & 16 deletions crates/sui-core/src/authority/authority_per_epoch_store.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

use fastcrypto_zkp::bn254::zk_login::{JwkId, OIDCProvider, JWK};
use fastcrypto_zkp::bn254::zk_login_api::ZkLoginEnv;
use futures::future::{join_all, select, Either};
use futures::FutureExt;
use itertools::izip;
Expand All @@ -26,13 +28,13 @@ use sui_types::transaction::{
CertifiedTransaction, SenderSignedData, SharedInputObject, TransactionDataAPI,
VerifiedCertificate, VerifiedSignedTransaction,
};
use sui_types::zk_login_util::OAuthProviderContent;
use tracing::{debug, error, info, trace, warn};
use typed_store::rocks::{
default_db_options, DBBatch, DBMap, DBOptions, MetricConf, TypedStoreError,
};
use typed_store::traits::{TableSummary, TypedStoreDebug};

use super::epoch_start_configuration::EpochStartConfigTrait;
use crate::authority::epoch_start_configuration::{EpochFlag, EpochStartConfiguration};
use crate::authority::{AuthorityStore, ResolverWrapper};
use crate::checkpoints::{
Expand All @@ -53,9 +55,10 @@ use mysten_common::sync::notify_once::NotifyOnce;
use mysten_common::sync::notify_read::NotifyRead;
use mysten_metrics::monitored_scope;
use prometheus::IntCounter;
use std::str::FromStr;
use sui_execution::{self, Executor};
use sui_macros::fail_point;
use sui_protocol_config::{ProtocolConfig, ProtocolVersion};
use sui_protocol_config::{Chain, ProtocolConfig, ProtocolVersion};
use sui_storage::mutex_table::{MutexGuard, MutexTable};
use sui_types::effects::{TransactionEffects, TransactionEffectsAPI};
use sui_types::executable_transaction::{
Expand All @@ -77,8 +80,6 @@ use tokio::time::Instant;
use typed_store::{retry_transaction_forever, Map};
use typed_store_derive::DBMapUtils;

use super::epoch_start_configuration::EpochStartConfigTrait;

/// The key where the latest consensus index is stored in the database.
// TODO: Make a single table (e.g., called `variables`) storing all our lonely variables in one place.
const LAST_CONSENSUS_INDEX_ADDR: u64 = 0;
Expand Down Expand Up @@ -309,8 +310,8 @@ pub struct AuthorityEpochTables {
pub(crate) executed_transactions_to_checkpoint:
DBMap<TransactionDigest, CheckpointSequenceNumber>,

/// Map from kid (key id) to the fetched OAuthProviderContent for that key.
oauth_provider_jwk: DBMap<String, OAuthProviderContent>,
/// Map from JwkId (iss, kid) to the fetched JWK for that key.
oauth_provider_jwk: DBMap<JwkId, JWK>,
}

fn signed_transactions_table_default_config() -> DBOptions {
Expand Down Expand Up @@ -392,7 +393,7 @@ impl AuthorityEpochTables {
Ok(self.last_consensus_index.get(&LAST_CONSENSUS_INDEX_ADDR)?)
}

fn load_oauth_provider_jwk(&self) -> SuiResult<HashMap<String, Arc<OAuthProviderContent>>> {
fn load_oauth_provider_jwk(&self) -> SuiResult<HashMap<JwkId, Arc<JWK>>> {
Ok(self
.oauth_provider_jwk
.unbounded_iter()
Expand Down Expand Up @@ -464,10 +465,25 @@ impl AuthorityPerEpochStore {
.load_oauth_provider_jwk()
.expect("Load oauth provider jwk at initialization cannot fail");

let signature_verifier =
SignatureVerifier::new(committee.clone(), signature_verifier_metrics);
for (_, v) in oauth_provider_jwk.iter() {
signature_verifier.insert_oauth_jwk(v);
let zklogin_env = match chain_identifier.chain() {
Chain::Mainnet => ZkLoginEnv::Prod,
_ => ZkLoginEnv::Test,
};

let supported_providers = protocol_config
.zklogin_supported_providers()
.iter()
.map(|s| OIDCProvider::from_str(s).expect("Invalid provider string"))
.collect::<Vec<_>>();

let signature_verifier = SignatureVerifier::new(
committee.clone(),
signature_verifier_metrics,
supported_providers,
zklogin_env,
);
for (jwk_id, jwk) in oauth_provider_jwk.iter() {
signature_verifier.insert_oauth_jwk(jwk_id, jwk);
}

let is_validator = committee.authority_index(&name).is_some();
Expand Down Expand Up @@ -2156,15 +2172,16 @@ impl AuthorityPerEpochStore {
}

// TODO: should be pub(crate) when it is inserted only from consensus
pub fn insert_oauth_jwk(&self, content: &OAuthProviderContent) {
if self.signature_verifier.insert_oauth_jwk(content) {
pub fn insert_oauth_jwk(&self, jwk_id: &JwkId, jwk: &JWK) {
if self.signature_verifier.insert_oauth_jwk(jwk_id, jwk) {
self.tables
.oauth_provider_jwk
.insert(&content.kid().to_string(), content)
.insert(jwk_id, jwk)
.expect("write to oauth_provider_jwk should not fail");
info!("Added new JWK with kid {}: {:?}", content.kid(), content);
// TODO: Remove old kid -> jwks.
info!("Added new JWK with id {:?}: {:?}", jwk_id, jwk);
} else {
info!("OAuth JWK with kid {} already exists", content.kid());
info!("JWK with id {:?} already exists", jwk_id);
}
}
}
Expand Down
69 changes: 49 additions & 20 deletions crates/sui-core/src/signature_verifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,21 @@
// SPDX-License-Identifier: Apache-2.0

use either::Either;
use fastcrypto_zkp::bn254::zk_login::JwkId;
use fastcrypto_zkp::bn254::zk_login::{OIDCProvider, JWK};
use fastcrypto_zkp::bn254::zk_login_api::ZkLoginEnv;
use futures::pin_mut;
use im::hashmap::HashMap as ImHashMap;
use itertools::izip;
use lru::LruCache;
use mysten_metrics::monitored_scope;
use parking_lot::{Mutex, MutexGuard, RwLock};
use prometheus::{register_int_counter_with_registry, IntCounter, Registry};
use shared_crypto::intent::Intent;
use std::hash::Hash;
use std::sync::Arc;
use sui_types::digests::SenderSignedDataDigest;
use sui_types::transaction::SenderSignedData;
use sui_types::{
committee::Committee,
crypto::{AuthoritySignInfoTrait, VerificationObligation},
Expand All @@ -20,19 +26,13 @@ use sui_types::{
messages_checkpoint::SignedCheckpointSummary,
signature::VerifyParams,
transaction::{CertifiedTransaction, VerifiedCertificate},
zk_login_util::OAuthProviderContent,
};

use mysten_metrics::monitored_scope;
use sui_types::digests::SenderSignedDataDigest;
use sui_types::transaction::SenderSignedData;
use tap::TapFallible;
use tokio::runtime::Handle;
use tokio::{
sync::oneshot,
time::{timeout, Duration},
};

// Maximum amount of time we wait for a batch to fill up before verifying a partial batch.
const BATCH_TIMEOUT_MS: Duration = Duration::from_millis(10);

Expand Down Expand Up @@ -92,22 +92,36 @@ pub struct SignatureVerifier {
certificate_cache: VerifiedDigestCache<CertificateDigest>,
signed_data_cache: VerifiedDigestCache<SenderSignedDataDigest>,

/// Map from kid (key id) to the fetched OAuthProviderContent for that key.
/// Map from JwkId (iss, kid) to the fetched JWK for that key.
/// We use an immutable data structure because verification of ZKLogins may be slow, so we
/// don't want to pass a reference to the map to the verify method, since that would lead to a
/// lengthy critical section. Instead, we use an immutable data structure which can be cloned
/// very cheaply.
oauth_provider_jwk: RwLock<ImHashMap<String, OAuthProviderContent>>,
oauth_provider_jwk: RwLock<ImHashMap<JwkId, JWK>>,

/// Params that contains a list of supported providers for ZKLogin and the environment (prod/test) the code runs in.
zk_login_params: ZkLoginParams,

queue: Mutex<CertBuffer>,
pub metrics: Arc<SignatureVerifierMetrics>,
}

/// Contains two parameters to pass in to verify a ZkLogin signature.
#[derive(Clone)]
struct ZkLoginParams {
/// A list of supported OAuth providers for ZkLogin.
pub supported_providers: Vec<OIDCProvider>,
/// The environment (prod/test) the code runs in. It decides which verifying key to use in fastcrypto.
pub env: ZkLoginEnv,
}

impl SignatureVerifier {
pub fn new_with_batch_size(
committee: Arc<Committee>,
batch_size: usize,
metrics: Arc<SignatureVerifierMetrics>,
supported_providers: Vec<OIDCProvider>,
env: ZkLoginEnv,
) -> Self {
Self {
committee,
Expand All @@ -122,11 +136,26 @@ impl SignatureVerifier {
oauth_provider_jwk: Default::default(),
queue: Mutex::new(CertBuffer::new(batch_size)),
metrics,
zk_login_params: ZkLoginParams {
supported_providers,
env,
},
}
}

pub fn new(committee: Arc<Committee>, metrics: Arc<SignatureVerifierMetrics>) -> Self {
Self::new_with_batch_size(committee, MAX_BATCH_SIZE, metrics)
pub fn new(
committee: Arc<Committee>,
metrics: Arc<SignatureVerifierMetrics>,
supported_providers: Vec<OIDCProvider>,
zklogin_env: ZkLoginEnv,
) -> Self {
Self::new_with_batch_size(
committee,
MAX_BATCH_SIZE,
metrics,
supported_providers,
zklogin_env,
)
}

/// Verifies all certs, returns Ok only if all are valid.
Expand Down Expand Up @@ -275,17 +304,14 @@ impl SignatureVerifier {
});
}

/// Insert a JWK into the verifier state. Returns true if the kid of the JWK has not already
/// Insert a JWK into the verifier state based on provider. Returns true if the kid of the JWK has not already
/// been inserted.
pub(crate) fn insert_oauth_jwk(&self, content: &OAuthProviderContent) -> bool {
pub(crate) fn insert_oauth_jwk(&self, jwk_id: &JwkId, jwk: &JWK) -> bool {
let mut oauth_provider_jwk = self.oauth_provider_jwk.write();

if oauth_provider_jwk.contains_key(content.kid()) {
if oauth_provider_jwk.contains_key(jwk_id) {
return false;
}

let kid = content.kid().to_string();
oauth_provider_jwk.insert(kid, content.clone());
oauth_provider_jwk.insert(jwk_id.clone(), jwk.clone());
true
}

Expand All @@ -294,7 +320,11 @@ impl SignatureVerifier {
.is_verified(signed_tx.full_message_digest(), || {
signed_tx.verify_epoch(self.committee.epoch())?;
let oauth_provider_jwk = self.oauth_provider_jwk.read().clone();
let aux_data = VerifyParams::new(oauth_provider_jwk);
let aux_data = VerifyParams::new(
oauth_provider_jwk,
self.zk_login_params.supported_providers.clone(),
self.zk_login_params.env.clone(),
);
signed_tx.verify_message_signature(&aux_data)
})
}
Expand Down Expand Up @@ -394,8 +424,7 @@ pub fn batch_verify_certificates(
certs: &[CertifiedTransaction],
) -> Vec<SuiResult> {
// certs.data() is assumed to be verified already by the caller.

let verify_params = VerifyParams::new(Default::default());
let verify_params = VerifyParams::new(Default::default(), Vec::new(), Default::default());
match batch_verify(committee, certs, &[]) {
Ok(_) => vec![Ok(()); certs.len()],

Expand Down
9 changes: 8 additions & 1 deletion crates/sui-core/src/unit_tests/batch_verification_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,13 +106,20 @@ async fn test_batch_verify() {

#[tokio::test(flavor = "multi_thread", worker_threads = 8)]
async fn test_async_verifier() {
use fastcrypto_zkp::bn254::zk_login_api::ZkLoginEnv;

let (committee, key_pairs) = Committee::new_simple_test_committee();
let committee = Arc::new(committee);
let key_pairs = Arc::new(key_pairs);

let registry = Registry::new();
let metrics = SignatureVerifierMetrics::new(&registry);
let verifier = Arc::new(SignatureVerifier::new(committee.clone(), metrics));
let verifier = Arc::new(SignatureVerifier::new(
committee.clone(),
metrics,
vec![],
ZkLoginEnv::Test,
));

let tasks: Vec<_> = (0..32)
.map(|_| {
Expand Down
Loading

0 comments on commit 78d693d

Please sign in to comment.