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

fix: add strong typing to Bn254Point #751

Merged
merged 2 commits into from
Mar 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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)
}
27 changes: 18 additions & 9 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, 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::zk_login_utils::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,7 +495,7 @@ 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()])
let salt_hash = poseidon_zk_login(vec![(&Bn254FrElement::from_str(salt).unwrap()).into()])
.unwrap()
.to_string();
assert!(verify_zk_login_id(&address, name, value, aud, iss, &salt_hash).is_ok());
Expand Down Expand Up @@ -583,10 +591,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
21 changes: 9 additions & 12 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::zk_login_utils::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![(&Bn254FrElement::from_str(salt)?).into()])?;
gen_address_seed_with_salt_hash(&salt_hash.to_string(), name, value, aud)
}

Expand All @@ -54,7 +58,7 @@ pub(crate) fn gen_address_seed_with_salt_hash(
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)?,
(&Bn254FrElement::from_str(salt_hash)?).into(),
])?
.to_string())
}
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())
}
28 changes: 11 additions & 17 deletions fastcrypto-zkp/src/bn254/zk_login.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ 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,
use crate::zk_login_utils::{
g1_affine_from_str_projective, g2_affine_from_str_projective, 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,12 @@ impl ZkLoginInputs {
return Err(FastCryptoError::GeneralError("Header too long".to_string()));
}

let addr_seed = to_field(&self.address_seed)?;
let addr_seed = (&self.address_seed).into();
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 = (&Bn254FrElement::from_str(&max_epoch.to_string())?).into();
let index_mod_4_f =
(&Bn254FrElement::from_str(&self.iss_base64_details.index_mod_4.to_string())?).into();

let iss_base64_f =
hash_ascii_str_to_field(&self.iss_base64_details.value, MAX_ISS_LEN_B64)?;
Expand Down Expand Up @@ -536,12 +536,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
Loading