Skip to content

Commit be6a5a6

Browse files
committed
Add an account contract with secp256r1 sig verification and test it end-to-end
1 parent 4d9b102 commit be6a5a6

11 files changed

Lines changed: 414 additions & 253 deletions

File tree

soroban-env-host/src/builtin_contracts/testutils.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,25 @@ pub(crate) fn sign_payload_for_ed25519(
256256
.unwrap()
257257
}
258258

259+
#[allow(dead_code)]
260+
pub(crate) fn sign_payload_for_secp256r1(
261+
host: &Host,
262+
signer: &p256::ecdsa::SigningKey,
263+
payload: &[u8],
264+
) -> BytesN<64> {
265+
use p256::ecdsa::Signature;
266+
let mut sig: Signature = signer.sign_prehash_recoverable(payload).unwrap().0;
267+
sig = sig.normalize_s().unwrap_or(sig);
268+
println!("produced signature {:x?}", sig.to_bytes());
269+
BytesN::<64>::try_from_val(
270+
host,
271+
&host
272+
.bytes_new_from_slice(sig.to_bytes().as_slice())
273+
.unwrap(),
274+
)
275+
.unwrap()
276+
}
277+
259278
#[allow(clippy::too_many_arguments)]
260279
pub(crate) fn create_account(
261280
host: &Host,

soroban-env-host/src/test/stellar_asset_contract.rs

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,9 @@ use crate::{
2727
Env, EnvBase, Host, HostError, LedgerInfo, Symbol, TryFromVal, TryIntoVal, Val,
2828
};
2929
use ed25519_dalek::SigningKey;
30+
use hex_literal::hex;
3031
use soroban_test_wasms::{
31-
ERR, INVOKE_CONTRACT, SAC_REENTRY_TEST_CONTRACT, SIMPLE_ACCOUNT_CONTRACT,
32+
ERR, INCREMENT, INVOKE_CONTRACT, SAC_REENTRY_TEST_CONTRACT, SIMPLE_ACCOUNT_CONTRACT,
3233
};
3334
use stellar_strkey::ed25519;
3435

@@ -3060,6 +3061,64 @@ fn test_custom_account_auth() {
30603061
.is_err());
30613062
}
30623063

3064+
#[allow(clippy::type_complexity)]
3065+
fn secp256r1_sign_fn<'a>(
3066+
host: &'a Host,
3067+
signing_key: &'a p256::ecdsa::SigningKey,
3068+
) -> Box<dyn Fn(&[u8]) -> Val + 'a> {
3069+
use crate::builtin_contracts::testutils::sign_payload_for_secp256r1;
3070+
Box::new(|payload: &[u8]| -> Val {
3071+
sign_payload_for_secp256r1(host, signing_key, payload).into()
3072+
})
3073+
}
3074+
3075+
#[test]
3076+
fn test_account_with_p256_signer() -> Result<(), HostError> {
3077+
use p256::ecdsa::SigningKey;
3078+
3079+
let host = Host::test_host_with_recording_footprint();
3080+
host.set_ledger_info(LedgerInfo {
3081+
protocol_version: crate::meta::get_ledger_protocol_version(crate::meta::INTERFACE_VERSION),
3082+
sequence_number: 123,
3083+
timestamp: 123456,
3084+
network_id: [5; 32],
3085+
base_reserve: 5_000_000,
3086+
min_persistent_entry_ttl: 4096,
3087+
min_temp_entry_ttl: 16,
3088+
max_entry_ttl: 6_312_000,
3089+
})?;
3090+
host.enable_debug()?;
3091+
3092+
let contract_addr_obj = host.register_test_contract_wasm(INCREMENT);
3093+
let contract_addr: Address = contract_addr_obj.try_into_val(&host)?;
3094+
// key pair taken from RFC 6979 Appendix 2.5 (NIST P-256 + SHA-256)
3095+
// <https://tools.ietf.org/html/rfc6979#appendix-A.2.5>
3096+
let x = hex!("C9AFA9D845BA75166B5C215767B1D6934E50C3DB36E89B127B8A622B120F6721");
3097+
let signing_key = SigningKey::from_bytes(&x.into()).unwrap();
3098+
let admin = TestSigner::AccountContract(AccountContractSigner {
3099+
address: contract_addr.clone(),
3100+
sign: secp256r1_sign_fn(&host, &signing_key),
3101+
});
3102+
// initialize the contract by calling its `init` with the secp256r1 public key
3103+
let verifying_key = host.bytes_new_from_slice(&hex!("0460FED4BA255A9D31C961EB74C6356D68C049B8923B61FA6CE669622E60F29FB67903FE1008B8BC99A41AE9E95628BC64F2F1B20C2D7E9F5177A3C294D4462299"))?;
3104+
let _ = host.call(
3105+
contract_addr_obj.clone(),
3106+
Symbol::try_from_small_str("init")?,
3107+
test_vec!(&host, verifying_key).into(),
3108+
)?;
3109+
3110+
authorize_single_invocation(&host, &admin, &contract_addr, "increment", test_vec![&host]);
3111+
3112+
let v = host.call(
3113+
contract_addr_obj,
3114+
Symbol::try_from_small_str("increment")?,
3115+
test_vec![&host].into(),
3116+
)?;
3117+
3118+
assert_eq!(v.get_payload(), Val::from_u32(1).as_val().get_payload());
3119+
Ok(())
3120+
}
3121+
30633122
#[test]
30643123
fn test_recording_auth_for_stellar_asset_contract() {
30653124
let test = StellarAssetContractTest::setup(function_name!());

soroban-env-host/src/vm/parsed_module.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,8 @@ impl ParsedModule {
300300
host,
301301
(ScErrorType::WasmVm, ScErrorCode::InvalidInput),
302302
"contract protocol number is newer than host",
303-
got_proto
303+
got_proto,
304+
want_proto
304305
));
305306
}
306307
Ok(())

soroban-test-wasms/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,4 +98,7 @@ mod curr {
9898

9999
pub const DEPLOYER_TEST_CONTRACT: &[u8] =
100100
include_bytes!("../wasm-workspace/opt/curr/test_deployer.wasm").as_slice();
101+
102+
pub const INCREMENT: &[u8] =
103+
include_bytes!("../wasm-workspace/opt/curr/increment.wasm").as_slice();
101104
}

0 commit comments

Comments
 (0)