Skip to content

Commit

Permalink
fix: Use strong type during deser
Browse files Browse the repository at this point in the history
  • Loading branch information
joyqvq committed Mar 26, 2024
1 parent 7219182 commit 9179252
Show file tree
Hide file tree
Showing 9 changed files with 413 additions and 148 deletions.
5 changes: 3 additions & 2 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions fastcrypto-zkp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ ff = { version = "0.13.0", features = ["derive"] }
typenum = "1.13.0"
lazy_static = "1.4.0"
itertools = "0.12.0"
thiserror = "1.0.40"

[dev-dependencies]
ark-bls12-377 = "0.4.0"
Expand Down
2 changes: 1 addition & 1 deletion fastcrypto-zkp/benches/zklogin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ mod zklogin_benches {
"25769832374-famecqrhe2gkebt5fvqms2263046lj96.apps.googleusercontent.com",
)
.unwrap();
let input = ZkLoginInputs::from_json("{\"proofPoints\":{\"a\":[\"8247215875293406890829839156897863742504615191361518281091302475904551111016\",\"6872980335748205979379321982220498484242209225765686471076081944034292159666\",\"1\"],\"b\":[[\"21419680064642047510915171723230639588631899775315750803416713283740137406807\",\"21566716915562037737681888858382287035712341650647439119820808127161946325890\"],[\"17867714710686394159919998503724240212517838710399045289784307078087926404555\",\"21812769875502013113255155836896615164559280911997219958031852239645061854221\"],[\"1\",\"0\"]],\"c\":[\"7530826803702928198368421787278524256623871560746240215547076095911132653214\",\"16244547936249959771862454850485726883972969173921727256151991751860694123976\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ\"}", &address_seed).unwrap();
let input = ZkLoginInputs::from_json("{\"proofPoints\":{\"a\":[\"8247215875293406890829839156897863742504615191361518281091302475904551111016\",\"6872980335748205979379321982220498484242209225765686471076081944034292159666\",\"1\"],\"b\":[[\"21419680064642047510915171723230639588631899775315750803416713283740137406807\",\"21566716915562037737681888858382287035712341650647439119820808127161946325890\"],[\"17867714710686394159919998503724240212517838710399045289784307078087926404555\",\"21812769875502013113255155836896615164559280911997219958031852239645061854221\"],[\"1\",\"0\"]],\"c\":[\"7530826803702928198368421787278524256623871560746240215547076095911132653214\",\"16244547936249959771862454850485726883972969173921727256151991751860694123976\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ\"}", &address_seed.to_string()).unwrap();
let kp = Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32]));
let mut eph_pubkey = vec![0x00];
eph_pubkey.extend(kp.public().as_ref());
Expand Down
2 changes: 1 addition & 1 deletion fastcrypto-zkp/src/bn254/unit_tests/zk_login_e2e_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,6 @@ async fn get_test_inputs(parsed_token: &str) -> (u64, Vec<u8>, ZkLoginInputs) {
let (sub, aud) = parse_and_validate_jwt(parsed_token).unwrap();
// Get the address seed.
let address_seed = gen_address_seed(user_salt, "sub", &sub, &aud).unwrap();
let zk_login_inputs = ZkLoginInputs::from_reader(reader, &address_seed).unwrap();
let zk_login_inputs = ZkLoginInputs::from_reader(reader, &address_seed.to_string()).unwrap();
(max_epoch, eph_pubkey, zk_login_inputs)
}
33 changes: 22 additions & 11 deletions fastcrypto-zkp/src/bn254/unit_tests/zk_login_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,13 @@ use std::str::FromStr;

use crate::bn254::poseidon::poseidon_zk_login;
use crate::bn254::utils::{
big_int_str_to_bytes, gen_address_seed, gen_address_seed_with_salt_hash, get_nonce,
get_zk_login_address,
gen_address_seed, gen_address_seed_with_salt_hash, get_nonce, get_zk_login_address,
};
use crate::bn254::zk_login::big_int_array_to_bits;
use crate::bn254::zk_login::bitarray_to_bytearray;
use crate::bn254::zk_login::{
base64_to_bitarray, convert_base, decode_base64_url, hash_ascii_str_to_field, hash_to_field,
parse_jwks, to_field, trim, verify_extended_claim, Claim, JWTDetails, JwkId,
parse_jwks, parse_fr_field_element, trim, verify_extended_claim, Claim, JWTDetails, JwkId,
};
use crate::bn254::zk_login::{fetch_jwks, OIDCProvider};
use crate::bn254::zk_login_api::ZkLoginEnv;
Expand All @@ -21,6 +20,7 @@ use crate::bn254::{
zk_login::{ZkLoginInputs, JWK},
zk_login_api::verify_zk_login,
};
use crate::circom::Bn254FrElement;
use ark_bn254::Fr;
use ark_std::rand::rngs::StdRng;
use ark_std::rand::SeedableRng;
Expand Down Expand Up @@ -109,7 +109,7 @@ async fn test_verify_zk_login_google() {
.unwrap();

// Get a proof from endpoint and serialize it.
let zk_login_inputs = ZkLoginInputs::from_json("{\"proofPoints\":{\"a\":[\"8247215875293406890829839156897863742504615191361518281091302475904551111016\",\"6872980335748205979379321982220498484242209225765686471076081944034292159666\",\"1\"],\"b\":[[\"21419680064642047510915171723230639588631899775315750803416713283740137406807\",\"21566716915562037737681888858382287035712341650647439119820808127161946325890\"],[\"17867714710686394159919998503724240212517838710399045289784307078087926404555\",\"21812769875502013113255155836896615164559280911997219958031852239645061854221\"],[\"1\",\"0\"]],\"c\":[\"7530826803702928198368421787278524256623871560746240215547076095911132653214\",\"16244547936249959771862454850485726883972969173921727256151991751860694123976\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ\"}", &address_seed).unwrap();
let zk_login_inputs = ZkLoginInputs::from_json("{\"proofPoints\":{\"a\":[\"8247215875293406890829839156897863742504615191361518281091302475904551111016\",\"6872980335748205979379321982220498484242209225765686471076081944034292159666\",\"1\"],\"b\":[[\"21419680064642047510915171723230639588631899775315750803416713283740137406807\",\"21566716915562037737681888858382287035712341650647439119820808127161946325890\"],[\"17867714710686394159919998503724240212517838710399045289784307078087926404555\",\"21812769875502013113255155836896615164559280911997219958031852239645061854221\"],[\"1\",\"0\"]],\"c\":[\"7530826803702928198368421787278524256623871560746240215547076095911132653214\",\"16244547936249959771862454850485726883972969173921727256151991751860694123976\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ\"}", &address_seed.to_string()).unwrap();
assert_eq!(
zk_login_inputs.get_kid(),
"6f7254101f56e41cf35c9926de84a2d552b4c6f1".to_string()
Expand All @@ -118,7 +118,10 @@ async fn test_verify_zk_login_google() {
zk_login_inputs.get_iss(),
OIDCProvider::Google.get_config().iss
);
assert_eq!(zk_login_inputs.get_address_seed(), address_seed);
assert_eq!(
zk_login_inputs.get_address_seed().to_string(),
address_seed.to_string()
);
assert_eq!(
get_zk_login_address(
zk_login_inputs.get_address_seed(),
Expand Down Expand Up @@ -190,6 +193,11 @@ fn test_parse_jwt_details() {

#[test]
fn test_decode_base64() {
assert_eq!(
decode_base64_url("aa", &1).unwrap_err(),
FastCryptoError::GeneralError("Invalid UTF8 string".to_string())
);

assert_eq!(
decode_base64_url("", &0).unwrap_err(),
FastCryptoError::GeneralError("Base64 string smaller than 2".to_string())
Expand Down Expand Up @@ -472,7 +480,7 @@ fn test_gen_seed() {
)
.unwrap();
assert_eq!(
address_seed,
address_seed.to_string(),
"16657007263003735230240998439420301694514420923267872433517882233836276100450".to_string()
);
}
Expand All @@ -487,9 +495,11 @@ fn test_verify_zk_login() {
let aud = "575519204237-msop9ep45u2uo98hapqmngv8d84qdc8k.apps.googleusercontent.com";
let salt = "6588741469050502421550140105345050859";
let iss = "https://accounts.google.com";
let salt_hash = poseidon_zk_login(vec![to_field(salt).unwrap()])
.unwrap()
.to_string();
let salt_hash = poseidon_zk_login(vec![
parse_fr_field_element(&Bn254FrElement::from_str(salt).unwrap()).unwrap()
])
.unwrap()
.to_string();
assert!(verify_zk_login_id(&address, name, value, aud, iss, &salt_hash).is_ok());

let address_seed = gen_address_seed_with_salt_hash(&salt_hash, name, value, aud).unwrap();
Expand Down Expand Up @@ -583,10 +593,11 @@ fn test_alternative_iss_for_google() {

let mut eph_pubkey_bytes = vec![0];
eph_pubkey_bytes.extend(
big_int_str_to_bytes(
BigUint::from_str(
"3598866369818193253063936208363210863933653800990958031560302098730308306242903464",
)
.unwrap(),
.unwrap()
.to_bytes_be(),
);
let mut all_jwk = ImHashMap::new();
all_jwk.insert(
Expand Down
31 changes: 14 additions & 17 deletions fastcrypto-zkp/src/bn254/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
use crate::bn254::poseidon::poseidon_zk_login;
use crate::bn254::zk_login::{OIDCProvider, ZkLoginInputsReader};
use crate::bn254::zk_login_api::Bn254Fr;
use crate::circom::{parse_fr_field_element, Bn254FrElement};
use fastcrypto::error::FastCryptoError;
use fastcrypto::hash::{Blake2b256, HashFunction};
use fastcrypto::rsa::Base64UrlUnpadded;
Expand All @@ -14,21 +15,24 @@ use serde::Deserialize;
use serde_json::json;
use std::str::FromStr;

use super::zk_login::{hash_ascii_str_to_field, to_field};
use super::zk_login::hash_ascii_str_to_field;

const ZK_LOGIN_AUTHENTICATOR_FLAG: u8 = 0x05;
const MAX_KEY_CLAIM_NAME_LENGTH: u8 = 32;
const MAX_KEY_CLAIM_VALUE_LENGTH: u8 = 115;
const MAX_AUD_VALUE_LENGTH: u8 = 145;

/// Calculate the Sui address based on address seed and address params.
pub fn get_zk_login_address(address_seed: &str, iss: &str) -> Result<[u8; 32], FastCryptoError> {
pub fn get_zk_login_address(
address_seed: &Bn254FrElement,
iss: &str,
) -> Result<[u8; 32], FastCryptoError> {
let mut hasher = Blake2b256::default();
hasher.update([ZK_LOGIN_AUTHENTICATOR_FLAG]);
let bytes = iss.as_bytes();
hasher.update([bytes.len() as u8]);
hasher.update(bytes);
hasher.update(big_int_str_to_bytes(address_seed)?);
hasher.update(address_seed.padded());
Ok(hasher.finalize().digest)
}

Expand All @@ -39,7 +43,7 @@ pub fn gen_address_seed(
value: &str, // i.e. the sub value
aud: &str, // i.e. the client ID
) -> Result<String, FastCryptoError> {
let salt_hash = poseidon_zk_login(vec![to_field(salt)?])?;
let salt_hash = poseidon_zk_login(vec![parse_fr_field_element(&Bn254FrElement::from_str(salt)?)?])?;
gen_address_seed_with_salt_hash(&salt_hash.to_string(), name, value, aud)
}

Expand All @@ -51,12 +55,12 @@ pub(crate) fn gen_address_seed_with_salt_hash(
aud: &str, // i.e. the client ID
) -> Result<String, FastCryptoError> {
Ok(poseidon_zk_login(vec![
hash_ascii_str_to_field(name, MAX_KEY_CLAIM_NAME_LENGTH)?,
hash_ascii_str_to_field(value, MAX_KEY_CLAIM_VALUE_LENGTH)?,
hash_ascii_str_to_field(aud, MAX_AUD_VALUE_LENGTH)?,
to_field(salt_hash)?,
])?
.to_string())
hash_ascii_str_to_field(name, MAX_KEY_CLAIM_NAME_LENGTH)?,
hash_ascii_str_to_field(value, MAX_KEY_CLAIM_VALUE_LENGTH)?,
hash_ascii_str_to_field(aud, MAX_AUD_VALUE_LENGTH)?,
parse_fr_field_element(&Bn254FrElement::from_str(salt_hash)?)?,
])?

Check warning on line 62 in fastcrypto-zkp/src/bn254/utils.rs

View check run for this annotation

Codecov / codecov/patch

fastcrypto-zkp/src/bn254/utils.rs#L62

Added line #L62 was not covered by tests
.to_string())
}

/// Return the OIDC URL for the given parameters. Crucially the nonce is computed.
Expand Down Expand Up @@ -196,10 +200,3 @@ pub fn split_to_two_frs(eph_pk_bytes: &[u8]) -> Result<(Bn254Fr, Bn254Fr), FastC
let eph_public_key_1 = Bn254Fr::from(second_bigint);
Ok((eph_public_key_0, eph_public_key_1))
}

/// Convert a big int string to a big endian bytearray.
pub fn big_int_str_to_bytes(value: &str) -> Result<Vec<u8>, FastCryptoError> {
Ok(BigUint::from_str(value)
.map_err(|_| FastCryptoError::InvalidInput)?
.to_bytes_be())
}
27 changes: 11 additions & 16 deletions fastcrypto-zkp/src/bn254/zk_login.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ use serde_json::Value;
use super::utils::split_to_two_frs;
use crate::bn254::poseidon::poseidon_zk_login;
use crate::circom::{
g1_affine_from_str_projective, g2_affine_from_str_projective, CircomG1, CircomG2,
g1_affine_from_str_projective, g2_affine_from_str_projective, parse_fr_field_element, Bn254FrElement,
CircomG1, CircomG2,
};
pub use ark_bn254::{Bn254, Fr as Bn254Fr};
pub use ark_ff::ToConstraintField;
Expand Down Expand Up @@ -301,7 +302,7 @@ pub struct ZkLoginInputs {
proof_points: ZkLoginProof,
iss_base64_details: Claim,
header_base64: String,
address_seed: String,
address_seed: Bn254FrElement,
#[serde(skip)]
jwt_details: JWTDetails,
}
Expand Down Expand Up @@ -334,17 +335,15 @@ impl ZkLoginInputs {
proof_points: reader.proof_points,
iss_base64_details: reader.iss_base64_details,
header_base64: reader.header_base64,
address_seed: address_seed.to_owned(),
address_seed: Bn254FrElement::from_str(address_seed)
.map_err(|_| FastCryptoError::InvalidInput)?,
jwt_details: reader.jwt_details,
}
.init()
}

/// Initialize JWTDetails by parsing header_base64 and iss_base64_details.
pub fn init(&mut self) -> Result<Self, FastCryptoError> {
if BigUint::from_str(&self.address_seed).is_err() {
return Err(FastCryptoError::InvalidInput);
}
self.jwt_details = JWTDetails::new(&self.header_base64, &self.iss_base64_details)?;
Ok(self.to_owned())
}
Expand All @@ -365,7 +364,7 @@ impl ZkLoginInputs {
}

/// Get the address seed string.
pub fn get_address_seed(&self) -> &str {
pub fn get_address_seed(&self) -> &Bn254FrElement {
&self.address_seed
}

Expand All @@ -380,11 +379,13 @@ impl ZkLoginInputs {
return Err(FastCryptoError::GeneralError("Header too long".to_string()));
}

let addr_seed = to_field(&self.address_seed)?;
let addr_seed = parse_fr_field_element(&self.address_seed)?;
let (first, second) = split_to_two_frs(eph_pk_bytes)?;

let max_epoch_f = to_field(&max_epoch.to_string())?;
let index_mod_4_f = to_field(&self.iss_base64_details.index_mod_4.to_string())?;
let max_epoch_f = parse_fr_field_element(&Bn254FrElement::from_str(&max_epoch.to_string())?)?;
let index_mod_4_f = parse_fr_field_element(&Bn254FrElement::from_str(
&self.iss_base64_details.index_mod_4.to_string(),
)?)?;

let iss_base64_f =
hash_ascii_str_to_field(&self.iss_base64_details.value, MAX_ISS_LEN_B64)?;
Expand Down Expand Up @@ -536,12 +537,6 @@ fn bitarray_to_bytearray(bits: &[u8]) -> FastCryptoResult<Vec<u8>> {
.collect())
}

/// Convert a bigint string to a field element.
pub fn to_field(val: &str) -> Result<Bn254Fr, FastCryptoError> {
Bn254Fr::from_str(val)
.map_err(|_| FastCryptoError::GeneralError("Convert to field error".to_string()))
}

/// Pads a stream of bytes and maps it to a field element
pub fn hash_ascii_str_to_field(str: &str, max_size: u8) -> Result<Bn254Fr, FastCryptoError> {
let str_padded = str_to_padded_char_codes(str, max_size)?;
Expand Down
Loading

0 comments on commit 9179252

Please sign in to comment.