11use super :: * ;
22use crate :: cost_constants:: { ECRECOVER_COST_ERGS , ECRECOVER_NATIVE_COST } ;
3+ use crypto:: secp256k1:: hooks:: DefaultSecp256k1Hooks ;
4+ use field_ops:: Secp256k1HooksWithOracle ;
35use zk_ee:: common_traits:: TryExtend ;
6+ use zk_ee:: oracle:: IOOracle ;
47use zk_ee:: out_of_return_memory;
5- use zk_ee:: system:: base_system_functions:: { Secp256k1ECRecoverErrors , SystemFunction } ;
8+ use zk_ee:: system:: base_system_functions:: Secp256k1ECRecoverErrors ;
69use zk_ee:: system:: errors:: { subsystem:: SubsystemError , system:: SystemError } ;
7- use zk_ee:: system:: Computational ;
10+ use zk_ee:: system:: { Computational , SystemFunctionExt } ;
811
912///
1013/// ecrecover system function implementation.
1114///
1215pub struct EcRecoverImpl ;
1316
14- impl < R : Resources > SystemFunction < R , Secp256k1ECRecoverErrors > for EcRecoverImpl {
17+ impl < R : Resources > SystemFunctionExt < R , Secp256k1ECRecoverErrors > for EcRecoverImpl {
1518 /// If the input size is less than expected - it will be padded with zeroes.
1619 /// If the input size is greater - redundant bytes will be ignored.
1720 /// If the input is invalid(v != 27|28 or failed to recover signer) returns `Ok(0)`.
1821 ///
1922 /// Returns `OutOfGas` if not enough resources provided.
20- fn execute < D : TryExtend < u8 > + ?Sized , A : core:: alloc:: Allocator + Clone > (
23+ fn execute < O : IOOracle , L , D : TryExtend < u8 > + ?Sized , A : core:: alloc:: Allocator + Clone > (
2124 input : & [ u8 ] ,
2225 output : & mut D ,
2326 resources : & mut R ,
27+ oracle : & mut O ,
28+ _logger : & mut L ,
2429 _allocator : A ,
2530 ) -> Result < ( ) , SubsystemError < Secp256k1ECRecoverErrors > > {
2631 Ok ( cycle_marker:: wrap_with_resources!(
2732 "ecrecover" ,
2833 resources,
29- { ecrecover_as_system_function_inner( input, output, resources) }
34+ // TODO: reconsider if we actually want to use the oracle based version here
35+ { ecrecover_as_system_function_inner( input, output, resources, Some ( oracle) ) }
3036 ) ?)
3137 }
3238}
3339
3440fn ecrecover_as_system_function_inner <
41+ O : IOOracle ,
3542 S : ?Sized + MinimalByteAddressableSlice ,
3643 D : ?Sized + TryExtend < u8 > ,
3744 R : Resources ,
3845> (
3946 src : & S ,
4047 dst : & mut D ,
4148 resources : & mut R ,
49+ oracle : Option < & mut O > ,
4250) -> Result < ( ) , SystemError > {
4351 resources. charge ( & R :: from_ergs_and_native (
4452 ECRECOVER_COST_ERGS ,
@@ -68,7 +76,14 @@ fn ecrecover_as_system_function_inner<
6876 return Ok ( ( ) ) ;
6977 }
7078
71- let Ok ( pk_bytes) = ecrecover_inner ( digest, r, s, rec_id) else {
79+ // on forward run we do not support oracle-based hooks
80+ let oracle = if cfg ! ( target_arch = "riscv32" ) {
81+ oracle
82+ } else {
83+ None
84+ } ;
85+
86+ let Ok ( pk_bytes) = ecrecover_inner ( digest, r, s, rec_id, oracle) else {
7287 return Ok ( ( ) ) ;
7388 } ;
7489
@@ -85,11 +100,12 @@ fn ecrecover_as_system_function_inner<
85100 Ok ( ( ) )
86101}
87102
88- pub fn ecrecover_inner (
103+ pub fn ecrecover_inner < O : IOOracle > (
89104 digest : & [ u8 ; 32 ] ,
90105 r : & [ u8 ; 32 ] ,
91106 s : & [ u8 ; 32 ] ,
92107 rec_id : u8 ,
108+ oracle : Option < & mut O > ,
93109) -> Result < crypto:: k256:: EncodedPoint , ( ) > {
94110 use crypto:: k256:: {
95111 ecdsa:: { hazmat:: bits2field, RecoveryId , Signature } ,
@@ -104,7 +120,22 @@ pub fn ecrecover_inner(
104120 & bits2field :: < crypto:: k256:: Secp256k1 > ( digest) . map_err ( |_| ( ) ) ?,
105121 ) ;
106122
107- let Ok ( pk) = crypto:: secp256k1:: recover ( & message, & signature, & recovery_id) else {
123+ let res = match oracle {
124+ Some ( oracle) => crypto:: secp256k1:: recover (
125+ & message,
126+ & signature,
127+ & recovery_id,
128+ & mut Secp256k1HooksWithOracle :: new ( oracle) ,
129+ ) ,
130+ None => crypto:: secp256k1:: recover (
131+ & message,
132+ & signature,
133+ & recovery_id,
134+ & mut DefaultSecp256k1Hooks ,
135+ ) ,
136+ } ;
137+
138+ let Ok ( pk) = res else {
108139 return Err ( ( ) ) ;
109140 } ;
110141
@@ -117,6 +148,7 @@ pub fn ecrecover_inner(
117148#[ cfg( test) ]
118149mod test {
119150 use super :: * ;
151+ use crate :: system_implementation:: flat_storage_model:: TestingTree ;
120152 use hex;
121153 use zk_ee:: reference_implementations:: BaseResources ;
122154 use zk_ee:: reference_implementations:: DecreasingNative ;
@@ -140,8 +172,13 @@ mod test {
140172
141173 let mut resources = <BaseResources < DecreasingNative > as Resource >:: FORMAL_INFINITE ;
142174
143- ecrecover_as_system_function_inner ( input. as_slice ( ) , & mut pubkey, & mut resources)
144- . expect ( "ecrecover" ) ;
175+ ecrecover_as_system_function_inner :: < TestingTree < false > , _ , _ , _ > (
176+ input. as_slice ( ) ,
177+ & mut pubkey,
178+ & mut resources,
179+ None ,
180+ )
181+ . expect ( "ecrecover" ) ;
145182 assert_eq ! ( pubkey. len( ) , 32 , "Size should be 32" ) ;
146183 assert_eq ! (
147184 pubkey, expected_pubkey,
@@ -156,8 +193,13 @@ mod test {
156193
157194 let mut resources = <BaseResources < DecreasingNative > as Resource >:: FORMAL_INFINITE ;
158195
159- ecrecover_as_system_function_inner ( input. as_slice ( ) , & mut pubkey, & mut resources)
160- . expect ( "ecrecover" ) ;
196+ ecrecover_as_system_function_inner :: < TestingTree < false > , _ , _ , _ > (
197+ input. as_slice ( ) ,
198+ & mut pubkey,
199+ & mut resources,
200+ None ,
201+ )
202+ . expect ( "ecrecover" ) ;
161203 assert_eq ! ( pubkey. len( ) , 0 , "Size should be 0" ) ;
162204 }
163205
@@ -173,8 +215,13 @@ mod test {
173215
174216 let mut resources = <BaseResources < DecreasingNative > as Resource >:: FORMAL_INFINITE ;
175217
176- ecrecover_as_system_function_inner ( input. as_slice ( ) , & mut pubkey, & mut resources)
177- . expect ( "ecrecover" ) ;
218+ ecrecover_as_system_function_inner :: < TestingTree < false > , _ , _ , _ > (
219+ input. as_slice ( ) ,
220+ & mut pubkey,
221+ & mut resources,
222+ None ,
223+ )
224+ . expect ( "ecrecover" ) ;
178225 assert_eq ! ( pubkey. len( ) , 0 , "Size should be 0 in case of error" ) ;
179226 }
180227
@@ -190,8 +237,13 @@ mod test {
190237
191238 let mut resources = <BaseResources < DecreasingNative > as Resource >:: FORMAL_INFINITE ;
192239
193- ecrecover_as_system_function_inner ( input. as_slice ( ) , & mut pubkey, & mut resources)
194- . expect ( "ecrecover" ) ;
240+ ecrecover_as_system_function_inner :: < TestingTree < false > , _ , _ , _ > (
241+ input. as_slice ( ) ,
242+ & mut pubkey,
243+ & mut resources,
244+ None ,
245+ )
246+ . expect ( "ecrecover" ) ;
195247 assert_eq ! ( pubkey. len( ) , 0 , "Size should be 0 in case of error" ) ;
196248 }
197249
@@ -213,9 +265,13 @@ mod test {
213265 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 99 , 249 , 114 , 95 , 16 , 115 , 88 , 201 , 17 , 91 , 201 ,
214266 216 , 108 , 114 , 221 , 88 , 35 , 233 , 177 , 230 ,
215267 ] ;
216-
217- ecrecover_as_system_function_inner ( input. as_slice ( ) , & mut pubkey, & mut resources)
218- . expect ( "ecrecover" ) ;
268+ ecrecover_as_system_function_inner :: < TestingTree < false > , _ , _ , _ > (
269+ input. as_slice ( ) ,
270+ & mut pubkey,
271+ & mut resources,
272+ None ,
273+ )
274+ . expect ( "ecrecover" ) ;
219275 assert_eq ! ( pubkey. len( ) , 32 , "Size should be 32" ) ;
220276 assert_eq ! (
221277 pubkey, expected_pubkey,
0 commit comments