@@ -10,7 +10,7 @@ use rand::{SeedableRng, rngs::StdRng};
1010
1111use crate :: {
1212 IotaAddress ,
13- base_types:: { ObjectID , dbg_addr} ,
13+ base_types:: { ObjectID , dbg_addr, random_object_ref } ,
1414 committee:: Committee ,
1515 crypto:: {
1616 AccountKeyPair , AuthorityKeyPair , AuthorityPublicKeyBytes , IotaKeyPair , Signature , Signer ,
@@ -22,7 +22,7 @@ use crate::{
2222 signature:: GenericSignature ,
2323 transaction:: {
2424 SenderSignedData , TEST_ONLY_GAS_UNIT_FOR_TRANSFER , Transaction , TransactionData ,
25- TransactionDataAPI ,
25+ TransactionDataAPI , TransactionKind ,
2626 } ,
2727} ;
2828
@@ -94,6 +94,27 @@ pub fn make_transaction_data(sender: IotaAddress) -> TransactionData {
9494 )
9595}
9696
97+ /// Make sponsored [`TransactionData`] with a transfer-IOTA programmable
98+ /// transaction and a random gas object, for use in tests.
99+ pub fn make_sponsored_transaction_data (
100+ sender : IotaAddress ,
101+ sponsor : IotaAddress ,
102+ ) -> TransactionData {
103+ let pt = {
104+ let mut builder = ProgrammableTransactionBuilder :: new ( ) ;
105+ builder. transfer_iota ( dbg_addr ( 2 ) , None ) ;
106+ builder. finish ( )
107+ } ;
108+ TransactionData :: new_with_gas_coins_allow_sponsor (
109+ TransactionKind :: new_programmable ( pt) ,
110+ sender,
111+ vec ! [ random_object_ref( ) ] ,
112+ TEST_ONLY_GAS_UNIT_FOR_TRANSFER , // gas price is 1
113+ 1 ,
114+ sponsor,
115+ )
116+ }
117+
97118/// Make a user signed transaction with the given sender and its keypair. This
98119/// is not verified or signed by authority.
99120pub fn make_transaction ( sender : IotaAddress , kp : & IotaKeyPair ) -> Transaction {
@@ -167,37 +188,123 @@ pub fn make_upgraded_multisig_tx() -> Transaction {
167188 ) )
168189}
169190
191+ /// Make a sponsored transaction where both sender and sponsor sign with regular
192+ /// (Ed25519) signatures, for use in tests.
193+ ///
194+ /// Returns the transaction together with the sender's and sponsor's addresses
195+ /// so callers can locate each signature within the transaction.
196+ pub fn make_sponsored_regular_sig_tx ( ) -> ( Transaction , IotaAddress , IotaAddress ) {
197+ let ( sender, sender_kp) : ( _ , AccountKeyPair ) = get_key_pair ( ) ;
198+ let ( sponsor, sponsor_kp) : ( _ , AccountKeyPair ) = get_key_pair ( ) ;
199+ let tx_data = make_sponsored_transaction_data ( sender, sponsor) ;
200+ let sender_sig: GenericSignature =
201+ Transaction :: signature_from_signer ( tx_data. clone ( ) , Intent :: iota_transaction ( ) , & sender_kp)
202+ . into ( ) ;
203+ let tx =
204+ to_sender_signed_transaction_with_optional_sponsor ( tx_data, sender_sig, Some ( & sponsor_kp) ) ;
205+ ( tx, sender, sponsor)
206+ }
207+
170208mod move_authenticator {
209+ use fastcrypto:: hash:: HashFunction ;
210+ use iota_sdk_types:: Digest ;
211+
171212 pub use crate :: move_authenticator:: MoveAuthenticator ;
172213 use crate :: {
173214 base_types:: IotaAddress ,
215+ crypto:: DefaultHash ,
174216 object:: OBJECT_START_VERSION ,
175217 signature:: GenericSignature ,
176218 transaction:: { CallArg , SenderSignedData , SharedObjectRef , Transaction } ,
177- utils:: make_transaction_data,
219+ utils:: { make_sponsored_transaction_data , make_transaction_data} ,
178220 } ;
179221
180222 /// Make a transaction signed with `MoveAuthenticator` for testing.
181223 pub fn make_move_authenticator_tx ( address : IotaAddress ) -> Transaction {
182224 let data = make_transaction_data ( address) ;
225+ let ( authenticator, _) = make_move_authenticator_sig ( address) ;
226+ Transaction :: new ( SenderSignedData :: new ( data, vec ! [ authenticator] ) )
227+ }
183228
184- // There is no a real Move account behind this address.
185- //
186- // TODO: if it is necessary, AA accounts need to be supported properly in the
187- // `AuthorityState` used for testing.
188- let self_call_arg = CallArg :: Shared ( SharedObjectRef {
189- object_id : address. into ( ) ,
190- initial_shared_version : OBJECT_START_VERSION ,
191- mutable : false ,
192- } ) ;
193- let authenticator = GenericSignature :: MoveAuthenticator ( MoveAuthenticator :: new_v1 (
229+ /// Build a [`GenericSignature::MoveAuthenticator`] and the underlying
230+ /// [`MoveAuthenticator`] for the given address, for use in tests.
231+ ///
232+ /// There is no real Move account behind this address.
233+ ///
234+ /// TODO: if it is necessary, AA accounts need to be supported properly in
235+ /// the `AuthorityState` used for testing.
236+ pub fn make_move_authenticator_sig (
237+ address : IotaAddress ,
238+ ) -> ( GenericSignature , MoveAuthenticator ) {
239+ let authenticator = MoveAuthenticator :: new_v1 (
194240 vec ! [ ] ,
195241 vec ! [ ] ,
196- self_call_arg,
242+ CallArg :: Shared ( SharedObjectRef {
243+ object_id : address. into ( ) ,
244+ initial_shared_version : OBJECT_START_VERSION ,
245+ mutable : false ,
246+ } ) ,
247+ ) ;
248+ let sig = GenericSignature :: MoveAuthenticator ( authenticator. clone ( ) ) ;
249+ ( sig, authenticator)
250+ }
251+
252+ /// Make a sponsored transaction where both sender and sponsor sign with
253+ /// [`MoveAuthenticator`], for use in tests.
254+ ///
255+ /// Returns the transaction together with the sender's and sponsor's
256+ /// [`MoveAuthenticator`] so callers can independently verify the expected
257+ /// auth digests.
258+ pub fn make_sponsored_move_authenticator_tx (
259+ sender_addr : IotaAddress ,
260+ sponsor_addr : IotaAddress ,
261+ ) -> ( Transaction , MoveAuthenticator , MoveAuthenticator ) {
262+ let ( sender_sig, sender_auth) = make_move_authenticator_sig ( sender_addr) ;
263+ let ( sponsor_sig, sponsor_auth) = make_move_authenticator_sig ( sponsor_addr) ;
264+ let tx_data = make_sponsored_transaction_data ( sender_addr, sponsor_addr) ;
265+ let tx = Transaction :: new ( SenderSignedData :: new (
266+ tx_data,
267+ vec ! [ sender_sig, sponsor_sig] ,
197268 ) ) ;
269+ ( tx, sender_auth, sponsor_auth)
270+ }
198271
199- Transaction :: new ( SenderSignedData :: new ( data, vec ! [ authenticator] ) )
272+ /// Compute the Blake2b256 hash of the serialized (flag-prefixed) bytes of a
273+ /// [`GenericSignature`], matching the digest used for
274+ /// non-[`MoveAuthenticator`] signatures by [`auth_digest_for_sig`].
275+ pub fn blake2b256_of_sig ( sig : & GenericSignature ) -> Digest {
276+ let mut hasher = DefaultHash :: default ( ) ;
277+ hasher. update ( sig. as_ref ( ) ) ;
278+ Digest :: new ( hasher. finalize ( ) . into ( ) )
200279 }
201280}
202281
203282pub use move_authenticator:: * ;
283+
284+ mod passkey {
285+ use fastcrypto:: secp256r1:: Secp256r1KeyPair ;
286+
287+ use crate :: {
288+ crypto:: { Signature , Signer , get_key_pair} ,
289+ passkey_authenticator:: PasskeyAuthenticator ,
290+ signature:: GenericSignature ,
291+ } ;
292+
293+ /// Build a [`GenericSignature::PasskeyAuthenticator`] backed by a
294+ /// freshly-generated Secp256r1 key pair, for use in tests.
295+ ///
296+ /// The challenge field is 32 zero-bytes encoded as base64url without
297+ /// padding, satisfying the length requirement without needing a real
298+ /// WebAuthn round-trip.
299+ pub fn make_passkey_authenticator_sig ( ) -> GenericSignature {
300+ let ( _, r1_kp) : ( _ , Secp256r1KeyPair ) = get_key_pair ( ) ;
301+ let user_sig: Signature = r1_kp. sign ( & [ 0u8 ; 32 ] ) ;
302+ let client_data_json = r#"{"type":"webauthn.get","challenge":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA","origin":"https://test.iota.org"}"# ;
303+ let passkey =
304+ PasskeyAuthenticator :: new_for_testing ( vec ! [ ] , client_data_json. to_string ( ) , user_sig)
305+ . unwrap ( ) ;
306+ GenericSignature :: PasskeyAuthenticator ( passkey)
307+ }
308+ }
309+
310+ pub use passkey:: * ;
0 commit comments