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

Implement cryptography ecalls and V-App Sdk support #38

Open
2 of 5 tasks
bigspider opened this issue Nov 13, 2024 · 0 comments
Open
2 of 5 tasks

Implement cryptography ecalls and V-App Sdk support #38

bigspider opened this issue Nov 13, 2024 · 0 comments

Comments

@bigspider
Copy link
Collaborator

bigspider commented Nov 13, 2024

Cryptography is the core functionality of the enclave, so it's worth designing it properly.
Ideally, we'd like to not map 1-on-1 with the C ledger SDK when the interface could be better (the Vanadium app can proxy to the C implementation appropriately). For the native implementation of the ecalls, we'll need to reimplement them as we no longer link with speculos binaries.

Tasks:

  • Bignums
  • BIP32
  • Hash Functions
  • Elliptic Curves
  • ECDSA/Schnorr signatures

Public-key only API?

One thing we might consider is if it's worth not allowing private keys derived from the seed in the V-App's RAM.
The reason for that is that while the RAM will be encrypted, yet the access pattern is not completely hidden (the client can see what pages are accessed and when); therefore, there is the potential footgun of implementing cryptographic algorithms where the access pattern depends on the bits of the secret. Probably not the case very often, but it can't be excluded.

Two options:

  • give access to private keys, clearly document the risk and explicitly name the functions as _dangerous (which forces the developers to at least think about the issue, and possible write safe wrappers around it)
  • provide an API that allows to allocate private keys in the Vanadium VM's memory, while the V-App only has access to it via a handle.

For now, I think the first option is the easiest, and most flexible (no limits to what crypto can be built). We can later add a safer API if necessary, with more experience on the V-App needs.
For the common needs (derive bip-32 public keys, sign messages with specific keys in the BIP-32 paths, the SDK can already provide a safe wrapper), so that V-Apps don't need to use unsafe blocks.

It might be useful to think about how to make sure that the private keys are always inside a single page, as that at least hides which part of the private key was accessed.

Vanadium-legacy ECALLs

General bignums:

    pub fn ecall_addm(
        r: *mut u8,
        a: *const u8,
        b: *const u8,
        m: *const u8,
        len: usize,
    ) -> bool;

    pub fn ecall_subm(
        r: *mut u8,
        a: *const u8,
        b: *const u8,
        m: *const u8,
        len: usize,
    ) -> bool;

    pub fn ecall_multm(
        r: *mut u8,
        a: *const u8,
        b: *const u8,
        m: *const u8,
        len: usize,
    ) -> bool;

    pub fn ecall_powm(
        r: *mut u8,
        a: *const u8,
        e: *const u8,
        len_e: usize,
        m: *const u8,
        len: usize,
    ) -> bool;

These are probably reasonable to keep as-is. No big changes required on the interface.

BIP32-related

    pub fn ecall_derive_node_bip32(
        curve: CxCurve,
        path: *const u32,
        path_count: usize,
        privkey_data: *mut u8,
        chain_code: *mut u8,
    ) -> bool;

    pub fn ecall_get_master_fingerprint(out: *mut [u8; 4]) -> bool;

ecall_derive_node_bip32 should probably be renamed, as it's actually more generic than that: only the secp256k1 curve is define in BIP32, while for other curves it's based on SLIP-10.

Instead of ecall_get_master_fingerprint, we could have a different version of derive_node that only returns the public key, and get_master_fingerprint could be implemented in the Rust SDK on top of it.

To be added: SLIP-21 symmetric key derivation (possibly not based on the implementation from the C SDK, which isn't very good and only supports 1 level of derivation IIRC).

Random bytes

    pub fn ecall_get_random_bytes(buffer: *mut u8, size: usize);

Useful to give access to the TRNG; keep verbatim.

Hash functions

    pub fn ecall_hash_update(
        hash_id: CxHashId,
        ctx: CtxHashGuest,
        buffer: *const u8,
        size: usize,
    ) -> bool;
    pub fn ecall_hash_final(hash_id: CxHashId, ctx: CtxHashGuest, buffer: *mut u8) -> bool;

These functions where somewhat weird to implement in vanadium-legacy (see the restore_ctx_from_guest/save_ctx_from_host pair of functions). The general principle of operating on the midstate and having a function to finalize, however, is sound and should be easily portable (e.g. for the native reimplementation in Rust).

Elliptic Curves

    pub fn ecall_cx_ecfp_generate_pair(
        curve: CxCurve,
        pubkey: &mut EcfpPublicKey,
        privkey: &mut EcfpPrivateKey,
        keep_privkey: bool,
    ) -> bool;
    pub fn ecall_cx_ecfp_add_point(
        curve: CxCurve,
        r: *mut u8,
        p: *const u8,
        q: *const u8,
    ) -> bool;
    pub fn ecall_cx_ecfp_scalar_mult(
        curve: CxCurve,
        p: *mut u8,
        k: *const u8,
        k_len: usize,
    ) -> bool;

In theory, these could be built without ecalls on top of bignums, but that's a lot more work, so the pragmatic choice is to just have ecalls for now; they can be deprecated in the future.

ecall_cx_ecfp_generate_pair has a weird interface, rethink a more appropriate one.

ECDSA / Schnorr signing

    pub fn ecall_ecdsa_sign(
        key: &EcfpPrivateKey,
        mode: i32,
        hash_id: CxMd,
        hash: *const u8,
        sig: *mut u8,
        sig_len: usize,
        parity: *mut i32) -> usize;
    pub fn ecall_ecdsa_verify(
        key: &EcfpPublicKey,
        hash: *const u8,
        sig: *const u8,
        sig_len: usize,
    ) -> bool;
    pub fn ecall_schnorr_sign(
        key: &EcfpPrivateKey,
        mode: u32,
        hash_id: CxMd,
        msg: *const u8,
        msg_len: usize,
        sig: *mut u8,
        sig_len: *mut usize) -> bool;
    pub fn ecall_schnorr_verify(
        key: &EcfpPublicKey,
        mode: u32,
        hash_id: CxMd,
        msg: *const u8,
        msg_len: usize,
        sig: *const u8,
        sig_len: usize) -> bool;

TBD if we need ecalls for these, or we instead can easily reimplement it in Vanadium SDK.

@bigspider bigspider changed the title Implement cryptography ecalls Implement cryptography ecalls and V-App Sdk support Nov 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant