1use crate::SuiAddress;
5use crate::crypto::{Signer, SuiKeyPair};
6use crate::multisig::{MultiSig, MultiSigPublicKey};
7use crate::programmable_transaction_builder::ProgrammableTransactionBuilder;
8use crate::transaction::{SenderSignedData, TEST_ONLY_GAS_UNIT_FOR_TRANSFER};
9use crate::{
10 base_types::{ObjectID, dbg_addr},
11 committee::Committee,
12 crypto::{
13 AccountKeyPair, AuthorityKeyPair, AuthorityPublicKeyBytes, DefaultHash, Signature,
14 SignatureScheme, get_key_pair, get_key_pair_from_rng,
15 },
16 object::Object,
17 signature::GenericSignature,
18 transaction::{Transaction, TransactionData},
19 zk_login_authenticator::ZkLoginAuthenticator,
20};
21use fastcrypto::ed25519::Ed25519KeyPair;
22use fastcrypto::hash::HashFunction;
23use fastcrypto::traits::KeyPair as KeypairTraits;
24use rand::SeedableRng;
25use rand::rngs::StdRng;
26use serde::Deserialize;
27use shared_crypto::intent::{Intent, IntentMessage};
28use std::collections::BTreeMap;
29
30#[derive(Deserialize)]
31pub struct TestData {
32 pub zklogin_inputs: String,
33 pub kp: String,
34 pub pk_bigint: String,
35 pub salt: String,
36 pub address_seed: String,
37}
38
39pub fn make_committee_key<R>(rand: &mut R) -> (Vec<AuthorityKeyPair>, Committee)
40where
41 R: rand::CryptoRng + rand::RngCore,
42{
43 make_committee_key_num(4, rand)
44}
45
46pub fn make_committee_key_num<R>(num: usize, rand: &mut R) -> (Vec<AuthorityKeyPair>, Committee)
47where
48 R: rand::CryptoRng + rand::RngCore,
49{
50 let mut authorities: BTreeMap<AuthorityPublicKeyBytes, u64> = BTreeMap::new();
51 let mut keys = Vec::new();
52
53 for _ in 0..num {
54 let (_, inner_authority_key): (_, AuthorityKeyPair) = get_key_pair_from_rng(rand);
55 authorities.insert(
56 AuthorityPublicKeyBytes::from(inner_authority_key.public()),
57 1,
58 );
59 keys.push(inner_authority_key);
60 }
61
62 let committee = Committee::new_for_testing_with_normalized_voting_power(0, authorities);
63 (keys, committee)
64}
65
66pub fn create_fake_transaction() -> Transaction {
69 let (sender, sender_key): (_, AccountKeyPair) = get_key_pair();
70 let recipient = dbg_addr(2);
71 let object_id = ObjectID::random();
72 let object = Object::immutable_with_id_for_testing(object_id);
73 let pt = {
74 let mut builder = ProgrammableTransactionBuilder::new();
75 builder.transfer_sui(recipient, None);
76 builder.finish()
77 };
78 let data = TransactionData::new_programmable(
79 sender,
80 vec![object.compute_object_reference()],
81 pt,
82 TEST_ONLY_GAS_UNIT_FOR_TRANSFER, 1,
84 );
85 to_sender_signed_transaction(data, &sender_key)
86}
87
88pub fn make_transaction_data(sender: SuiAddress) -> TransactionData {
89 let object = Object::immutable_with_id_for_testing(ObjectID::random_from_rng(
90 &mut StdRng::from_seed([0; 32]),
91 ));
92 let pt = {
93 let mut builder = ProgrammableTransactionBuilder::new();
94 builder.transfer_sui(dbg_addr(2), None);
95 builder.finish()
96 };
97 TransactionData::new_programmable(
98 sender,
99 vec![object.compute_object_reference()],
100 pt,
101 TEST_ONLY_GAS_UNIT_FOR_TRANSFER, 1,
103 )
104}
105
106pub fn make_transaction(sender: SuiAddress, kp: &SuiKeyPair) -> Transaction {
109 let data = make_transaction_data(sender);
110 Transaction::from_data_and_signer(data, vec![kp])
111}
112
113pub fn to_sender_signed_transaction(
115 data: TransactionData,
116 signer: &dyn Signer<Signature>,
117) -> Transaction {
118 to_sender_signed_transaction_with_multi_signers(data, vec![signer])
119}
120
121pub fn to_sender_signed_transaction_with_multi_signers(
122 data: TransactionData,
123 signers: Vec<&dyn Signer<Signature>>,
124) -> Transaction {
125 Transaction::from_data_and_signer(data, signers)
126}
127
128mod zk_login {
129 use fastcrypto_zkp::bn254::zk_login::{JWK, JwkId, ZkLoginInputs};
130 use shared_crypto::intent::PersonalMessage;
131
132 use crate::{crypto::PublicKey, zk_login_util::get_zklogin_inputs};
133
134 use super::*;
135 pub static DEFAULT_ADDRESS_SEED: &str =
136 "20794788559620669596206457022966176986688727876128223628113916380927502737911";
137 pub static SHORT_ADDRESS_SEED: &str =
138 "380704556853533152350240698167704405529973457670972223618755249929828551006";
139
140 pub const PINNED_V1_PROOF_JSON: &str = r#"{"proofPoints":{"a":["3010136044534492475575413496484577590932720513683681989179363462925612714982","5652552440722407852175866026012563042753395701135168680885840271325003476209","1"],"b":[["4134651808856881772397689190468686413285935393238712522589459332601848471034","20925849764837854473271908435319609501643424506601952398791677633465938999818"],["16706593113195287380129955552431425955520047611810267551522210853347280177225","8975261226848675342214968602342036744422056685641356205140655491003281432470"],["1","0"]],"c":["14516934896859103165306714687867025901326990259356520077875194067697843674675","12419034695817580775970400081639888434145575090674091981609146109263143679873","1"]},"issBase64Details":{"value":"wiaXNzIjoiaHR0cHM6Ly9vYXV0aC5zdWkuaW8iLC","indexMod4":2},"headerBase64":"eyJraWQiOiJzdWkta2V5LWlkIiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYifQ"}"#;
145 pub const PINNED_V2_PROOF_JSON: &str = r#"{"proofPoints":{"a":["10290383706848897825088985381697541801790334043318488983431378625753497718833","17591517929249273401895310772015184603780222740894596527224318218206984537104","1"],"b":[["3918033264923917639046061736301179481793021691718139448529347745111416321846","18123684393181543832037347354416686302931880789657446564169805732802329293676"],["5501473627788010270179873817591115039637415124881199561215844494127224527091","5357636725999458520558358539710311237463411851594252917784356338840007452395"],["1","0"]],"c":["14357495699847490388821026099380711662414404327434223254697278410014042621999","18065473806655831852488138949447369308006710206520416428472279919490765303978","1"]},"issBase64Details":{"value":"wiaXNzIjoiaHR0cHM6Ly9qd3QtdGVzdGVyLm15c3RlbmxhYnMuY29tIiw","indexMod4":2},"headerBase64":"eyJraWQiOiJzdWkta2V5LWlkLTgxOTIiLCJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9"}"#;
146 pub const PINNED_PROOF_ADDRESS_SEED: &str =
147 "1930628255822123795956154519923524356793387287437090556144422698180443693114";
148 pub const PINNED_V1_JWK_ID_JSON: &str = r#"{"iss":"https://oauth.sui.io","kid":"sui-key-id"}"#;
149 pub const PINNED_V1_JWK_JSON: &str = r#"{"kty":"RSA","e":"AQAB","n":"wdar6dBP7b88u6o190uXBK4yPS76OxFjiHDPwOyJwJiiAE3YRq8y_pfyQVua9nEasgrPfEBzVoC5QCld8NAC88uvbNKyoLZ6w5KlFjp88q2Sfy7nAzh3I-AnjsL6zl43NZrKep4_Nmb5nJeafcEi6B5MsYYDWW1Nn26O7ob9IWRNWcaTKhOhqDzbiN_66azN-NgaP_uHjlu1xuMV0kRt-luLSTXJS3S2n8PVNCxr3Gr2oViUpP8kSa-0i5vsg3gNtSfBY97AbChwOnyazj_PoaVD6zbEC4L5gvRZJA6vyoAWF_ZumvkwC3fxcFIBnSKMlGzS_Z-bUyQDCQy_BG9AOw","alg":"RS256"}"#;
150 pub const PINNED_V2_JWK_ID_JSON: &str =
151 r#"{"iss":"https://jwt-tester.mystenlabs.com","kid":"sui-key-id-8192"}"#;
152 pub const PINNED_V2_JWK_JSON: &str = r#"{"kty":"RSA","e":"AQAB","n":"lViYJOuLB6EZenCimgyWrwOH_QBEkCZxSIEfcQgP5MrZkRlohbrTAN1YpXGRaqugp9A4mRzCmi9ddXscpRBSsLefdPJJLG8lQZ2qrw6X2-6HD5kDFd6-K7JZS-_GOEfr5xGEDm8_MS_SorbmneKspL0n4MPYWH8qke4OBFCwL6WzGBU9rqDuvhYmafmkvVvOtHIqekBxNrCud7Spv43BHdiBM0V-jUquuNM3oK97i_GVLjGfwrGRpR3tK4nva_ryiHh9Ajs68If7-ZhIoLJ05lRsHJJpqsloiEqlCZwhge9zEMnNkoaIzdQr-xLy0GPnr5W0gikjlSGYiInfx9ITADwK3W33xdOB7npM7lqJY73Njbuw8hBQicU8t0M0gvvWfmh1KDeA5IqffZgue-ka9Jj1nrYmZtd0JimQpPDUiGbLv69gQJZcLVQWf9z6mVC4gNm8VU2OafssnolrvNndC3wIm8AgqzVzn_DIOcMQdhIe8jTF3hu1_6R4Id3KoA5Hb3uI2H86-8RjhSG2wKb3zi44yKSmxEDhzl7i450PQX64JK4ftv5jb9vSw5unpikmVvGlGsuvrqWFuWKBcrcXLgyar8pGvRO8fR9ifDHSj-D2fBiLnhK0-iqsJeU8XnfJhUvKxSjXejwsoQeLqlgq9-PgCDP3dE61fkqGpJ1UZjZ44Q9Vh4YLCPAO6oX8btXSkwreuP5m0UtWgFsc-ynWbt6NYS7JlsMtJNWybM4_auqRdil_cPMwFsUgjocztGLeG304YH-GehmyBJyGKuDIiXL9RfLoZ35jKawrWJb4UqckKWV5kOKeXsXdKtMw96ABFumcnhrzxAsqwshS5a2lT8P7Cdd9g3T1JXI7JM1AnJU9_gPXmJoc3yEFNf-JxEf00URoy2xUusyyxYdTswLJp3NQP4VjrAGwnsp7gHKC-V-mJ21FpQCHsV0JQ-1x-E3du9hkpsjTtGkffetEsV8k9enbkudox7WIlsnPcA8y7aY4lnaBqLLSzaj2GOf4KTN4cRpcPzOmSvgcVVYYQXDjRw45X86P1WJG8UDl6Wkl044tAdQRuIxW8QVzBFWWxeXcoagOBKn1_DV0RKUX9Ud4LLauy81rUNfoAcnolz9nippTBEZA_4OOBvXhdngCYaoZyjAkmYdPhKIkghGhKoVVKiEJ1Ua6nUr3zB9WFlTO9lODeV9h0tgKGtKGu3UBeaRCQSMv9gZK-eGIpcqjsqK_rEf4htdDZUBzfOJ0VtCiFYUUBPiuJNuIf9xQGVDE7qZufK1irvGug8jvWSWzB4pGLP75PnPH7B9axnXrxssaIR90Y3Vr9ih_ptzcfNrwD_wiGHUTy698FHu2fXp51HbSEQ","alg":"RS256"}"#;
153
154 pub fn pinned_jwks() -> im::HashMap<JwkId, JWK> {
156 [
157 (PINNED_V1_JWK_ID_JSON, PINNED_V1_JWK_JSON),
158 (PINNED_V2_JWK_ID_JSON, PINNED_V2_JWK_JSON),
159 ]
160 .into_iter()
161 .map(|(id, jwk)| {
162 (
163 serde_json::from_str(id).unwrap(),
164 serde_json::from_str(jwk).unwrap(),
165 )
166 })
167 .collect()
168 }
169
170 pub fn load_test_vectors(path: &str) -> Vec<(SuiKeyPair, PublicKey, ZkLoginInputs)> {
171 let file = std::fs::File::open(path).expect("Unable to open file");
173
174 let test_datum: Vec<TestData> = serde_json::from_reader(file).unwrap();
175 let mut res = vec![];
176 for test in test_datum {
177 let kp = SuiKeyPair::decode(&test.kp).unwrap();
178 let inputs =
179 ZkLoginInputs::from_json(&test.zklogin_inputs, &test.address_seed).unwrap();
180 let pk_zklogin = PublicKey::from_zklogin_inputs(&inputs).unwrap();
181 res.push((kp, pk_zklogin, inputs));
182 }
183 res
184 }
185 pub fn get_one_zklogin_inputs(path: &str) -> String {
186 let file = std::fs::File::open(path).expect("Unable to open file");
187
188 let test_data: Vec<TestData> = serde_json::from_reader(file).unwrap();
189 test_data[1].zklogin_inputs.clone()
190 }
191
192 pub fn get_zklogin_user_address() -> SuiAddress {
193 thread_local! {
194 static USER_ADDRESS: SuiAddress = {
195 let mut hasher = DefaultHash::default();
197 hasher.update([SignatureScheme::ZkLoginAuthenticator.flag()]);
198 let inputs = get_zklogin_inputs();
199 let iss_bytes = inputs.get_iss().as_bytes();
200 hasher.update([iss_bytes.len() as u8]);
201 hasher.update(iss_bytes);
202 hasher.update(inputs.get_address_seed().unpadded());
203 SuiAddress::from_bytes(hasher.finalize().digest).unwrap()
204 };
205 }
206 USER_ADDRESS.with(|a| *a)
207 }
208
209 fn get_zklogin_user_key() -> SuiKeyPair {
210 SuiKeyPair::Ed25519(Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32])))
211 }
212
213 fn get_inputs_with_bad_address_seed() -> ZkLoginInputs {
214 thread_local! {
215 static ZKLOGIN_INPUTS: ZkLoginInputs = ZkLoginInputs::from_json("{\"proofPoints\":{\"a\":[\"17276311605393076686048412951904952585208929623427027497902331765285829154985\",\"2195957390349729412627479867125563520760023859523358729791332629632025124364\",\"1\"],\"b\":[[\"10285059021604767951039627893758482248204478992077021270802057708215366770814\",\"20086937595807139308592304218494658586282197458549968652049579308384943311509\"],[\"7481123765095657256931104563876569626157448050870256177668773471703520958615\",\"11912752790863530118410797223176516777328266521602785233083571774104055633375\"],[\"1\",\"0\"]],\"c\":[\"15742763887654796666500488588763616323599882100448686869458326409877111249163\",\"6112916537574993759490787691149241262893771114597679488354854987586060572876\",\"1\"]},\"issBase64Details\":{\"value\":\"wiaXNzIjoiaHR0cHM6Ly9pZC50d2l0Y2gudHYvb2F1dGgyIiw\",\"indexMod4\":2},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEifQ\"}", SHORT_ADDRESS_SEED).unwrap(); }
216 ZKLOGIN_INPUTS.with(|a| a.clone())
217 }
218
219 pub fn get_legacy_zklogin_user_address() -> SuiAddress {
220 thread_local! {
221 static USER_ADDRESS: SuiAddress = {
222 let inputs = get_inputs_with_bad_address_seed();
223 SuiAddress::from(&PublicKey::from_zklogin_inputs(&inputs).unwrap())
224 };
225 }
226 USER_ADDRESS.with(|a| *a)
227 }
228
229 pub fn sign_zklogin_personal_msg(data: PersonalMessage) -> (SuiAddress, GenericSignature) {
230 let inputs = get_zklogin_inputs();
231 let msg = IntentMessage::new(Intent::personal_message(), data);
232 let s = Signature::new_secure(&msg, &get_zklogin_user_key());
233 let authenticator =
234 GenericSignature::ZkLoginAuthenticator(ZkLoginAuthenticator::new(inputs, 10, s));
235 let address = get_zklogin_user_address();
236 (address, authenticator)
237 }
238
239 pub fn sign_zklogin_tx_with_default_proof(
240 data: TransactionData,
241 legacy: bool,
242 ) -> (SuiAddress, Transaction, GenericSignature) {
243 let inputs = if legacy {
244 get_inputs_with_bad_address_seed()
245 } else {
246 get_zklogin_inputs()
247 };
248
249 sign_zklogin_tx(&get_zklogin_user_key(), inputs, data)
250 }
251
252 pub fn sign_zklogin_tx(
253 user_key: &SuiKeyPair,
254 proof: ZkLoginInputs,
255 data: TransactionData,
256 ) -> (SuiAddress, Transaction, GenericSignature) {
257 let tx = Transaction::from_data_and_signer(data.clone(), vec![user_key]);
258
259 let s = match tx.inner().tx_signatures.first().unwrap() {
260 GenericSignature::Signature(s) => s,
261 _ => panic!("Expected a signature"),
262 };
263
264 let authenticator =
266 GenericSignature::ZkLoginAuthenticator(ZkLoginAuthenticator::new(proof, 10, s.clone()));
267
268 let tx = Transaction::new(SenderSignedData::new(
269 tx.transaction_data().clone(),
270 vec![authenticator.clone()],
271 ));
272 (data.execution_parts().1, tx, authenticator)
273 }
274
275 pub fn make_zklogin_tx(
276 address: SuiAddress,
277 legacy: bool,
278 ) -> (SuiAddress, Transaction, GenericSignature) {
279 let data = make_transaction_data(address);
280 sign_zklogin_tx_with_default_proof(data, legacy)
281 }
282
283 pub fn keys() -> Vec<SuiKeyPair> {
284 let mut seed = StdRng::from_seed([0; 32]);
285 let kp1: SuiKeyPair = SuiKeyPair::Ed25519(get_key_pair_from_rng(&mut seed).1);
286 let kp2: SuiKeyPair = SuiKeyPair::Secp256k1(get_key_pair_from_rng(&mut seed).1);
287 let kp3: SuiKeyPair = SuiKeyPair::Secp256r1(get_key_pair_from_rng(&mut seed).1);
288 vec![kp1, kp2, kp3]
289 }
290
291 pub fn make_upgraded_multisig_tx() -> Transaction {
292 let keys = keys();
293 let pk1 = &keys[0].public();
294 let pk2 = &keys[1].public();
295 let pk3 = &keys[2].public();
296
297 let multisig_pk = MultiSigPublicKey::new(
298 vec![pk1.clone(), pk2.clone(), pk3.clone()],
299 vec![1, 1, 1],
300 2,
301 )
302 .unwrap();
303 let addr = SuiAddress::from(&multisig_pk);
304 let tx = make_transaction(addr, &keys[0]);
305
306 let msg = IntentMessage::new(Intent::sui_transaction(), tx.transaction_data().clone());
307 let sig1 = Signature::new_secure(&msg, &keys[0]).into();
308 let sig2 = Signature::new_secure(&msg, &keys[1]).into();
309
310 let multi_sig1 = MultiSig::combine(vec![sig1, sig2], multisig_pk).unwrap();
312 Transaction::new(SenderSignedData::new(
313 tx.transaction_data().clone(),
314 vec![GenericSignature::MultiSig(multi_sig1)],
315 ))
316 }
317}
318pub use zk_login::*;