From 5ad5cab49c169c89531c126e8850ae5705b64e00 Mon Sep 17 00:00:00 2001 From: Chloe Martin Date: Mon, 27 Oct 2025 16:11:26 +0100 Subject: [PATCH 01/12] feat(crypto): Add ability to create a private key from a mnemonic --- bindings/go/iota_sdk_ffi/iota_sdk_ffi.go | 89 +++++++++++++++ bindings/go/iota_sdk_ffi/iota_sdk_ffi.h | 44 ++++++++ bindings/kotlin/lib/iota_sdk/iota_sdk_ffi.kt | 93 ++++++++++++++++ bindings/python/lib/iota_sdk_ffi.py | 97 +++++++++++++++++ crates/iota-crypto/Cargo.toml | 5 + crates/iota-crypto/src/ed25519.rs | 34 +++++- crates/iota-crypto/src/lib.rs | 102 +++++++++++++++--- crates/iota-crypto/src/secp256k1.rs | 36 ++++++- crates/iota-crypto/src/secp256r1.rs | 36 ++++++- crates/iota-crypto/src/simple.rs | 96 +++++++++++++---- crates/iota-sdk-ffi/Cargo.toml | 2 +- crates/iota-sdk-ffi/src/crypto/ed25519.rs | 8 +- crates/iota-sdk-ffi/src/crypto/secp256k1.rs | 8 +- crates/iota-sdk-ffi/src/crypto/secp256r1.rs | 8 +- crates/iota-sdk-ffi/src/crypto/simple.rs | 9 +- crates/iota-sdk-types/src/crypto/signature.rs | 22 ++-- crates/iota-sdk/Cargo.toml | 4 + .../examples/generate_ed25519_address.rs | 2 +- 18 files changed, 629 insertions(+), 66 deletions(-) diff --git a/bindings/go/iota_sdk_ffi/iota_sdk_ffi.go b/bindings/go/iota_sdk_ffi/iota_sdk_ffi.go index d5f36ae3e..df7e9a647 100644 --- a/bindings/go/iota_sdk_ffi/iota_sdk_ffi.go +++ b/bindings/go/iota_sdk_ffi/iota_sdk_ffi.go @@ -7064,6 +7064,15 @@ func uniffiCheckChecksums() { } } { + checksum := rustCall(func(_uniffiStatus *C.RustCallStatus) C.uint16_t { + return C.uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_mnemonic() + }) + if checksum != 8176 { + // If this happens try cleaning and rebuilding your project + panic("iota_sdk_ffi: uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_mnemonic: UniFFI API checksum mismatch") + } + } + { checksum := rustCall(func(_uniffiStatus *C.RustCallStatus) C.uint16_t { return C.uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_pem() }) @@ -8306,6 +8315,15 @@ func uniffiCheckChecksums() { } } { + checksum := rustCall(func(_uniffiStatus *C.RustCallStatus) C.uint16_t { + return C.uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_mnemonic() + }) + if checksum != 1434 { + // If this happens try cleaning and rebuilding your project + panic("iota_sdk_ffi: uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_mnemonic: UniFFI API checksum mismatch") + } + } + { checksum := rustCall(func(_uniffiStatus *C.RustCallStatus) C.uint16_t { return C.uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_pem() }) @@ -8441,6 +8459,15 @@ func uniffiCheckChecksums() { } } { + checksum := rustCall(func(_uniffiStatus *C.RustCallStatus) C.uint16_t { + return C.uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_mnemonic() + }) + if checksum != 18331 { + // If this happens try cleaning and rebuilding your project + panic("iota_sdk_ffi: uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_mnemonic: UniFFI API checksum mismatch") + } + } + { checksum := rustCall(func(_uniffiStatus *C.RustCallStatus) C.uint16_t { return C.uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_pem() }) @@ -8594,6 +8621,15 @@ func uniffiCheckChecksums() { } } { + checksum := rustCall(func(_uniffiStatus *C.RustCallStatus) C.uint16_t { + return C.uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_mnemonic() + }) + if checksum != 10138 { + // If this happens try cleaning and rebuilding your project + panic("iota_sdk_ffi: uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_mnemonic: UniFFI API checksum mismatch") + } + } + { checksum := rustCall(func(_uniffiStatus *C.RustCallStatus) C.uint16_t { return C.uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_pem() }) @@ -12640,6 +12676,19 @@ func Ed25519PrivateKeyFromDer(bytes []byte) (*Ed25519PrivateKey, error) { } } +// Construct the private key from a mnemonic phrase +func Ed25519PrivateKeyFromMnemonic(phrase string) (*Ed25519PrivateKey, error) { + _uniffiRV, _uniffiErr := rustCallWithError[SdkFfiError](FfiConverterSdkFfiError{},func(_uniffiStatus *C.RustCallStatus) unsafe.Pointer { + return C.uniffi_iota_sdk_ffi_fn_constructor_ed25519privatekey_from_mnemonic(FfiConverterStringINSTANCE.Lower(phrase),_uniffiStatus) + }) + if _uniffiErr != nil { + var _uniffiDefaultValue *Ed25519PrivateKey + return _uniffiDefaultValue, _uniffiErr + } else { + return FfiConverterEd25519PrivateKeyINSTANCE.Lift(_uniffiRV), nil + } +} + // Deserialize PKCS#8-encoded private key from PEM. func Ed25519PrivateKeyFromPem(s string) (*Ed25519PrivateKey, error) { _uniffiRV, _uniffiErr := rustCallWithError[SdkFfiError](FfiConverterSdkFfiError{},func(_uniffiStatus *C.RustCallStatus) unsafe.Pointer { @@ -21166,6 +21215,19 @@ func Secp256k1PrivateKeyFromDer(bytes []byte) (*Secp256k1PrivateKey, error) { } } +// Construct the private key from a mnemonic phrase +func Secp256k1PrivateKeyFromMnemonic(phrase string) (*Secp256k1PrivateKey, error) { + _uniffiRV, _uniffiErr := rustCallWithError[SdkFfiError](FfiConverterSdkFfiError{},func(_uniffiStatus *C.RustCallStatus) unsafe.Pointer { + return C.uniffi_iota_sdk_ffi_fn_constructor_secp256k1privatekey_from_mnemonic(FfiConverterStringINSTANCE.Lower(phrase),_uniffiStatus) + }) + if _uniffiErr != nil { + var _uniffiDefaultValue *Secp256k1PrivateKey + return _uniffiDefaultValue, _uniffiErr + } else { + return FfiConverterSecp256k1PrivateKeyINSTANCE.Lift(_uniffiRV), nil + } +} + // Deserialize PKCS#8-encoded private key from PEM. func Secp256k1PrivateKeyFromPem(s string) (*Secp256k1PrivateKey, error) { _uniffiRV, _uniffiErr := rustCallWithError[SdkFfiError](FfiConverterSdkFfiError{},func(_uniffiStatus *C.RustCallStatus) unsafe.Pointer { @@ -22008,6 +22070,19 @@ func Secp256r1PrivateKeyFromDer(bytes []byte) (*Secp256r1PrivateKey, error) { } } +// Construct the private key from a mnemonic phrase +func Secp256r1PrivateKeyFromMnemonic(phrase string) (*Secp256r1PrivateKey, error) { + _uniffiRV, _uniffiErr := rustCallWithError[SdkFfiError](FfiConverterSdkFfiError{},func(_uniffiStatus *C.RustCallStatus) unsafe.Pointer { + return C.uniffi_iota_sdk_ffi_fn_constructor_secp256r1privatekey_from_mnemonic(FfiConverterStringINSTANCE.Lower(phrase),_uniffiStatus) + }) + if _uniffiErr != nil { + var _uniffiDefaultValue *Secp256r1PrivateKey + return _uniffiDefaultValue, _uniffiErr + } else { + return FfiConverterSecp256r1PrivateKeyINSTANCE.Lift(_uniffiRV), nil + } +} + // Deserialize PKCS#8-encoded private key from PEM. func Secp256r1PrivateKeyFromPem(s string) (*Secp256r1PrivateKey, error) { _uniffiRV, _uniffiErr := rustCallWithError[SdkFfiError](FfiConverterSdkFfiError{},func(_uniffiStatus *C.RustCallStatus) unsafe.Pointer { @@ -22858,6 +22933,20 @@ func SimpleKeypairFromEd25519(keypair *Ed25519PrivateKey) *SimpleKeypair { })) } +// Construct the private key from a mnemonic phrase and the signature +// scheme +func SimpleKeypairFromMnemonic(phrase string, scheme SignatureScheme) (*SimpleKeypair, error) { + _uniffiRV, _uniffiErr := rustCallWithError[SdkFfiError](FfiConverterSdkFfiError{},func(_uniffiStatus *C.RustCallStatus) unsafe.Pointer { + return C.uniffi_iota_sdk_ffi_fn_constructor_simplekeypair_from_mnemonic(FfiConverterStringINSTANCE.Lower(phrase), FfiConverterSignatureSchemeINSTANCE.Lower(scheme),_uniffiStatus) + }) + if _uniffiErr != nil { + var _uniffiDefaultValue *SimpleKeypair + return _uniffiDefaultValue, _uniffiErr + } else { + return FfiConverterSimpleKeypairINSTANCE.Lift(_uniffiRV), nil + } +} + // Deserialize PKCS#8-encoded private key from PEM. func SimpleKeypairFromPem(s string) (*SimpleKeypair, error) { _uniffiRV, _uniffiErr := rustCallWithError[SdkFfiError](FfiConverterSdkFfiError{},func(_uniffiStatus *C.RustCallStatus) unsafe.Pointer { diff --git a/bindings/go/iota_sdk_ffi/iota_sdk_ffi.h b/bindings/go/iota_sdk_ffi/iota_sdk_ffi.h index b527dec55..d9cd8abf0 100644 --- a/bindings/go/iota_sdk_ffi/iota_sdk_ffi.h +++ b/bindings/go/iota_sdk_ffi/iota_sdk_ffi.h @@ -1168,6 +1168,11 @@ void* uniffi_iota_sdk_ffi_fn_constructor_ed25519privatekey_from_bech32(RustBuffe void* uniffi_iota_sdk_ffi_fn_constructor_ed25519privatekey_from_der(RustBuffer bytes, RustCallStatus *out_status ); #endif +#ifndef UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_FN_CONSTRUCTOR_ED25519PRIVATEKEY_FROM_MNEMONIC +#define UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_FN_CONSTRUCTOR_ED25519PRIVATEKEY_FROM_MNEMONIC +void* uniffi_iota_sdk_ffi_fn_constructor_ed25519privatekey_from_mnemonic(RustBuffer phrase, RustCallStatus *out_status +); +#endif #ifndef UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_FN_CONSTRUCTOR_ED25519PRIVATEKEY_FROM_PEM #define UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_FN_CONSTRUCTOR_ED25519PRIVATEKEY_FROM_PEM void* uniffi_iota_sdk_ffi_fn_constructor_ed25519privatekey_from_pem(RustBuffer s, RustCallStatus *out_status @@ -3368,6 +3373,11 @@ void* uniffi_iota_sdk_ffi_fn_constructor_secp256k1privatekey_from_bech32(RustBuf void* uniffi_iota_sdk_ffi_fn_constructor_secp256k1privatekey_from_der(RustBuffer bytes, RustCallStatus *out_status ); #endif +#ifndef UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_FN_CONSTRUCTOR_SECP256K1PRIVATEKEY_FROM_MNEMONIC +#define UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_FN_CONSTRUCTOR_SECP256K1PRIVATEKEY_FROM_MNEMONIC +void* uniffi_iota_sdk_ffi_fn_constructor_secp256k1privatekey_from_mnemonic(RustBuffer phrase, RustCallStatus *out_status +); +#endif #ifndef UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_FN_CONSTRUCTOR_SECP256K1PRIVATEKEY_FROM_PEM #define UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_FN_CONSTRUCTOR_SECP256K1PRIVATEKEY_FROM_PEM void* uniffi_iota_sdk_ffi_fn_constructor_secp256k1privatekey_from_pem(RustBuffer s, RustCallStatus *out_status @@ -3612,6 +3622,11 @@ void* uniffi_iota_sdk_ffi_fn_constructor_secp256r1privatekey_from_bech32(RustBuf void* uniffi_iota_sdk_ffi_fn_constructor_secp256r1privatekey_from_der(RustBuffer bytes, RustCallStatus *out_status ); #endif +#ifndef UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_FN_CONSTRUCTOR_SECP256R1PRIVATEKEY_FROM_MNEMONIC +#define UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_FN_CONSTRUCTOR_SECP256R1PRIVATEKEY_FROM_MNEMONIC +void* uniffi_iota_sdk_ffi_fn_constructor_secp256r1privatekey_from_mnemonic(RustBuffer phrase, RustCallStatus *out_status +); +#endif #ifndef UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_FN_CONSTRUCTOR_SECP256R1PRIVATEKEY_FROM_PEM #define UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_FN_CONSTRUCTOR_SECP256R1PRIVATEKEY_FROM_PEM void* uniffi_iota_sdk_ffi_fn_constructor_secp256r1privatekey_from_pem(RustBuffer s, RustCallStatus *out_status @@ -3866,6 +3881,11 @@ void* uniffi_iota_sdk_ffi_fn_constructor_simplekeypair_from_der(RustBuffer bytes void* uniffi_iota_sdk_ffi_fn_constructor_simplekeypair_from_ed25519(void* keypair, RustCallStatus *out_status ); #endif +#ifndef UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_FN_CONSTRUCTOR_SIMPLEKEYPAIR_FROM_MNEMONIC +#define UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_FN_CONSTRUCTOR_SIMPLEKEYPAIR_FROM_MNEMONIC +void* uniffi_iota_sdk_ffi_fn_constructor_simplekeypair_from_mnemonic(RustBuffer phrase, RustBuffer scheme, RustCallStatus *out_status +); +#endif #ifndef UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_FN_CONSTRUCTOR_SIMPLEKEYPAIR_FROM_PEM #define UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_FN_CONSTRUCTOR_SIMPLEKEYPAIR_FROM_PEM void* uniffi_iota_sdk_ffi_fn_constructor_simplekeypair_from_pem(RustBuffer s, RustCallStatus *out_status @@ -11152,6 +11172,12 @@ uint16_t uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_bech32( #define UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_CHECKSUM_CONSTRUCTOR_ED25519PRIVATEKEY_FROM_DER uint16_t uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_der(void +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_CHECKSUM_CONSTRUCTOR_ED25519PRIVATEKEY_FROM_MNEMONIC +#define UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_CHECKSUM_CONSTRUCTOR_ED25519PRIVATEKEY_FROM_MNEMONIC +uint16_t uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_mnemonic(void + ); #endif #ifndef UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_CHECKSUM_CONSTRUCTOR_ED25519PRIVATEKEY_FROM_PEM @@ -11980,6 +12006,12 @@ uint16_t uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_bech3 #define UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_CHECKSUM_CONSTRUCTOR_SECP256K1PRIVATEKEY_FROM_DER uint16_t uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_der(void +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_CHECKSUM_CONSTRUCTOR_SECP256K1PRIVATEKEY_FROM_MNEMONIC +#define UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_CHECKSUM_CONSTRUCTOR_SECP256K1PRIVATEKEY_FROM_MNEMONIC +uint16_t uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_mnemonic(void + ); #endif #ifndef UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_CHECKSUM_CONSTRUCTOR_SECP256K1PRIVATEKEY_FROM_PEM @@ -12070,6 +12102,12 @@ uint16_t uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_bech3 #define UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_CHECKSUM_CONSTRUCTOR_SECP256R1PRIVATEKEY_FROM_DER uint16_t uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_der(void +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_CHECKSUM_CONSTRUCTOR_SECP256R1PRIVATEKEY_FROM_MNEMONIC +#define UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_CHECKSUM_CONSTRUCTOR_SECP256R1PRIVATEKEY_FROM_MNEMONIC +uint16_t uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_mnemonic(void + ); #endif #ifndef UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_CHECKSUM_CONSTRUCTOR_SECP256R1PRIVATEKEY_FROM_PEM @@ -12172,6 +12210,12 @@ uint16_t uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_der(void #define UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_CHECKSUM_CONSTRUCTOR_SIMPLEKEYPAIR_FROM_ED25519 uint16_t uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_ed25519(void +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_CHECKSUM_CONSTRUCTOR_SIMPLEKEYPAIR_FROM_MNEMONIC +#define UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_CHECKSUM_CONSTRUCTOR_SIMPLEKEYPAIR_FROM_MNEMONIC +uint16_t uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_mnemonic(void + ); #endif #ifndef UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_CHECKSUM_CONSTRUCTOR_SIMPLEKEYPAIR_FROM_PEM diff --git a/bindings/kotlin/lib/iota_sdk/iota_sdk_ffi.kt b/bindings/kotlin/lib/iota_sdk/iota_sdk_ffi.kt index ad7d09bae..2d23bd535 100644 --- a/bindings/kotlin/lib/iota_sdk/iota_sdk_ffi.kt +++ b/bindings/kotlin/lib/iota_sdk/iota_sdk_ffi.kt @@ -2881,6 +2881,14 @@ internal interface UniffiForeignFutureCompleteVoid : com.sun.jna.Callback { + + + + + + + + @@ -4395,6 +4403,8 @@ fun uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_bech32( ): Short fun uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_der( ): Short +fun uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_mnemonic( +): Short fun uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_pem( ): Short fun uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_generate( @@ -4671,6 +4681,8 @@ fun uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_bech32( ): Short fun uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_der( ): Short +fun uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_mnemonic( +): Short fun uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_pem( ): Short fun uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_generate( @@ -4701,6 +4713,8 @@ fun uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_bech32( ): Short fun uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_der( ): Short +fun uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_mnemonic( +): Short fun uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_pem( ): Short fun uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_generate( @@ -4735,6 +4749,8 @@ fun uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_der( ): Short fun uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_ed25519( ): Short +fun uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_mnemonic( +): Short fun uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_pem( ): Short fun uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_secp256k1( @@ -5222,6 +5238,8 @@ fun uniffi_iota_sdk_ffi_fn_constructor_ed25519privatekey_from_bech32(`value`: Ru ): Pointer fun uniffi_iota_sdk_ffi_fn_constructor_ed25519privatekey_from_der(`bytes`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): Pointer +fun uniffi_iota_sdk_ffi_fn_constructor_ed25519privatekey_from_mnemonic(`phrase`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, +): Pointer fun uniffi_iota_sdk_ffi_fn_constructor_ed25519privatekey_from_pem(`s`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): Pointer fun uniffi_iota_sdk_ffi_fn_constructor_ed25519privatekey_generate(uniffi_out_err: UniffiRustCallStatus, @@ -6092,6 +6110,8 @@ fun uniffi_iota_sdk_ffi_fn_constructor_secp256k1privatekey_from_bech32(`value`: ): Pointer fun uniffi_iota_sdk_ffi_fn_constructor_secp256k1privatekey_from_der(`bytes`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): Pointer +fun uniffi_iota_sdk_ffi_fn_constructor_secp256k1privatekey_from_mnemonic(`phrase`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, +): Pointer fun uniffi_iota_sdk_ffi_fn_constructor_secp256k1privatekey_from_pem(`s`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): Pointer fun uniffi_iota_sdk_ffi_fn_constructor_secp256k1privatekey_generate(uniffi_out_err: UniffiRustCallStatus, @@ -6188,6 +6208,8 @@ fun uniffi_iota_sdk_ffi_fn_constructor_secp256r1privatekey_from_bech32(`value`: ): Pointer fun uniffi_iota_sdk_ffi_fn_constructor_secp256r1privatekey_from_der(`bytes`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): Pointer +fun uniffi_iota_sdk_ffi_fn_constructor_secp256r1privatekey_from_mnemonic(`phrase`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, +): Pointer fun uniffi_iota_sdk_ffi_fn_constructor_secp256r1privatekey_from_pem(`s`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): Pointer fun uniffi_iota_sdk_ffi_fn_constructor_secp256r1privatekey_generate(uniffi_out_err: UniffiRustCallStatus, @@ -6288,6 +6310,8 @@ fun uniffi_iota_sdk_ffi_fn_constructor_simplekeypair_from_der(`bytes`: RustBuffe ): Pointer fun uniffi_iota_sdk_ffi_fn_constructor_simplekeypair_from_ed25519(`keypair`: Pointer,uniffi_out_err: UniffiRustCallStatus, ): Pointer +fun uniffi_iota_sdk_ffi_fn_constructor_simplekeypair_from_mnemonic(`phrase`: RustBuffer.ByValue,`scheme`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, +): Pointer fun uniffi_iota_sdk_ffi_fn_constructor_simplekeypair_from_pem(`s`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): Pointer fun uniffi_iota_sdk_ffi_fn_constructor_simplekeypair_from_secp256k1(`keypair`: Pointer,uniffi_out_err: UniffiRustCallStatus, @@ -9657,6 +9681,9 @@ private fun uniffiCheckApiChecksums(lib: IntegrityCheckingUniffiLib) { if (lib.uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_der() != 42838.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } + if (lib.uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_mnemonic() != 8176.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } if (lib.uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_pem() != 53776.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } @@ -10071,6 +10098,9 @@ private fun uniffiCheckApiChecksums(lib: IntegrityCheckingUniffiLib) { if (lib.uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_der() != 45448.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } + if (lib.uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_mnemonic() != 1434.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } if (lib.uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_pem() != 20937.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } @@ -10116,6 +10146,9 @@ private fun uniffiCheckApiChecksums(lib: IntegrityCheckingUniffiLib) { if (lib.uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_der() != 63595.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } + if (lib.uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_mnemonic() != 18331.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } if (lib.uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_pem() != 28166.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } @@ -10167,6 +10200,9 @@ private fun uniffiCheckApiChecksums(lib: IntegrityCheckingUniffiLib) { if (lib.uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_ed25519() != 22142.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } + if (lib.uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_mnemonic() != 10138.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } if (lib.uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_pem() != 2041.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } @@ -18189,6 +18225,20 @@ open class Ed25519PrivateKey: Disposable, AutoCloseable, Ed25519PrivateKeyInterf + /** + * Construct the private key from a mnemonic phrase + */ + @Throws(SdkFfiException::class) fun `fromMnemonic`(`phrase`: kotlin.String): Ed25519PrivateKey { + return FfiConverterTypeEd25519PrivateKey.lift( + uniffiRustCallWithError(SdkFfiException) { _status -> + UniffiLib.INSTANCE.uniffi_iota_sdk_ffi_fn_constructor_ed25519privatekey_from_mnemonic( + FfiConverterString.lower(`phrase`),_status) +} + ) + } + + + /** * Deserialize PKCS#8-encoded private key from PEM. */ @@ -34573,6 +34623,20 @@ open class Secp256k1PrivateKey: Disposable, AutoCloseable, Secp256k1PrivateKeyIn + /** + * Construct the private key from a mnemonic phrase + */ + @Throws(SdkFfiException::class) fun `fromMnemonic`(`phrase`: kotlin.String): Secp256k1PrivateKey { + return FfiConverterTypeSecp256k1PrivateKey.lift( + uniffiRustCallWithError(SdkFfiException) { _status -> + UniffiLib.INSTANCE.uniffi_iota_sdk_ffi_fn_constructor_secp256k1privatekey_from_mnemonic( + FfiConverterString.lower(`phrase`),_status) +} + ) + } + + + /** * Deserialize PKCS#8-encoded private key from PEM. */ @@ -36320,6 +36384,20 @@ open class Secp256r1PrivateKey: Disposable, AutoCloseable, Secp256r1PrivateKeyIn + /** + * Construct the private key from a mnemonic phrase + */ + @Throws(SdkFfiException::class) fun `fromMnemonic`(`phrase`: kotlin.String): Secp256r1PrivateKey { + return FfiConverterTypeSecp256r1PrivateKey.lift( + uniffiRustCallWithError(SdkFfiException) { _status -> + UniffiLib.INSTANCE.uniffi_iota_sdk_ffi_fn_constructor_secp256r1privatekey_from_mnemonic( + FfiConverterString.lower(`phrase`),_status) +} + ) + } + + + /** * Deserialize PKCS#8-encoded private key from PEM. */ @@ -38034,6 +38112,21 @@ open class SimpleKeypair: Disposable, AutoCloseable, SimpleKeypairInterface + /** + * Construct the private key from a mnemonic phrase and the signature + * scheme + */ + @Throws(SdkFfiException::class) fun `fromMnemonic`(`phrase`: kotlin.String, `scheme`: SignatureScheme): SimpleKeypair { + return FfiConverterTypeSimpleKeypair.lift( + uniffiRustCallWithError(SdkFfiException) { _status -> + UniffiLib.INSTANCE.uniffi_iota_sdk_ffi_fn_constructor_simplekeypair_from_mnemonic( + FfiConverterString.lower(`phrase`),FfiConverterTypeSignatureScheme.lower(`scheme`),_status) +} + ) + } + + + /** * Deserialize PKCS#8-encoded private key from PEM. */ diff --git a/bindings/python/lib/iota_sdk_ffi.py b/bindings/python/lib/iota_sdk_ffi.py index 7ffe7ac7e..051986d40 100644 --- a/bindings/python/lib/iota_sdk_ffi.py +++ b/bindings/python/lib/iota_sdk_ffi.py @@ -1951,6 +1951,8 @@ def _uniffi_check_api_checksums(lib): raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") if lib.uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_der() != 42838: raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_mnemonic() != 8176: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") if lib.uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_pem() != 53776: raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") if lib.uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_generate() != 53932: @@ -2227,6 +2229,8 @@ def _uniffi_check_api_checksums(lib): raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") if lib.uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_der() != 45448: raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_mnemonic() != 1434: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") if lib.uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_pem() != 20937: raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") if lib.uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_generate() != 49496: @@ -2257,6 +2261,8 @@ def _uniffi_check_api_checksums(lib): raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") if lib.uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_der() != 63595: raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_mnemonic() != 18331: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") if lib.uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_pem() != 28166: raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") if lib.uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_generate() != 47736: @@ -2291,6 +2297,8 @@ def _uniffi_check_api_checksums(lib): raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") if lib.uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_ed25519() != 22142: raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_mnemonic() != 10138: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") if lib.uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_pem() != 2041: raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") if lib.uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_secp256k1() != 46546: @@ -3338,6 +3346,11 @@ class _UniffiForeignFutureStructVoid(ctypes.Structure): ctypes.POINTER(_UniffiRustCallStatus), ) _UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_ed25519privatekey_from_der.restype = ctypes.c_void_p +_UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_ed25519privatekey_from_mnemonic.argtypes = ( + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_ed25519privatekey_from_mnemonic.restype = ctypes.c_void_p _UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_ed25519privatekey_from_pem.argtypes = ( _UniffiRustBuffer, ctypes.POINTER(_UniffiRustCallStatus), @@ -5577,6 +5590,11 @@ class _UniffiForeignFutureStructVoid(ctypes.Structure): ctypes.POINTER(_UniffiRustCallStatus), ) _UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_secp256k1privatekey_from_der.restype = ctypes.c_void_p +_UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_secp256k1privatekey_from_mnemonic.argtypes = ( + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_secp256k1privatekey_from_mnemonic.restype = ctypes.c_void_p _UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_secp256k1privatekey_from_pem.argtypes = ( _UniffiRustBuffer, ctypes.POINTER(_UniffiRustCallStatus), @@ -5826,6 +5844,11 @@ class _UniffiForeignFutureStructVoid(ctypes.Structure): ctypes.POINTER(_UniffiRustCallStatus), ) _UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_secp256r1privatekey_from_der.restype = ctypes.c_void_p +_UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_secp256r1privatekey_from_mnemonic.argtypes = ( + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_secp256r1privatekey_from_mnemonic.restype = ctypes.c_void_p _UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_secp256r1privatekey_from_pem.argtypes = ( _UniffiRustBuffer, ctypes.POINTER(_UniffiRustCallStatus), @@ -6085,6 +6108,12 @@ class _UniffiForeignFutureStructVoid(ctypes.Structure): ctypes.POINTER(_UniffiRustCallStatus), ) _UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_simplekeypair_from_ed25519.restype = ctypes.c_void_p +_UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_simplekeypair_from_mnemonic.argtypes = ( + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_simplekeypair_from_mnemonic.restype = ctypes.c_void_p _UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_simplekeypair_from_pem.argtypes = ( _UniffiRustBuffer, ctypes.POINTER(_UniffiRustCallStatus), @@ -11177,6 +11206,9 @@ class _UniffiForeignFutureStructVoid(ctypes.Structure): _UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_der.argtypes = ( ) _UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_der.restype = ctypes.c_uint16 +_UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_mnemonic.argtypes = ( +) +_UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_mnemonic.restype = ctypes.c_uint16 _UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_pem.argtypes = ( ) _UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_pem.restype = ctypes.c_uint16 @@ -11591,6 +11623,9 @@ class _UniffiForeignFutureStructVoid(ctypes.Structure): _UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_der.argtypes = ( ) _UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_der.restype = ctypes.c_uint16 +_UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_mnemonic.argtypes = ( +) +_UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_mnemonic.restype = ctypes.c_uint16 _UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_pem.argtypes = ( ) _UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_pem.restype = ctypes.c_uint16 @@ -11636,6 +11671,9 @@ class _UniffiForeignFutureStructVoid(ctypes.Structure): _UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_der.argtypes = ( ) _UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_der.restype = ctypes.c_uint16 +_UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_mnemonic.argtypes = ( +) +_UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_mnemonic.restype = ctypes.c_uint16 _UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_pem.argtypes = ( ) _UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_pem.restype = ctypes.c_uint16 @@ -11687,6 +11725,9 @@ class _UniffiForeignFutureStructVoid(ctypes.Structure): _UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_ed25519.argtypes = ( ) _UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_ed25519.restype = ctypes.c_uint16 +_UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_mnemonic.argtypes = ( +) +_UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_mnemonic.restype = ctypes.c_uint16 _UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_pem.argtypes = ( ) _UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_pem.restype = ctypes.c_uint16 @@ -28547,6 +28588,19 @@ def from_der(cls, bytes: "bytes"): _UniffiConverterBytes.lower(bytes)) return cls._make_instance_(pointer) + @classmethod + def from_mnemonic(cls, phrase: "str"): + """ + Construct the private key from a mnemonic phrase + """ + + _UniffiConverterString.check_lower(phrase) + + # Call the (fallible) function before creating any half-baked object instances. + pointer = _uniffi_rust_call_with_error(_UniffiConverterTypeSdkFfiError,_UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_ed25519privatekey_from_mnemonic, + _UniffiConverterString.lower(phrase)) + return cls._make_instance_(pointer) + @classmethod def from_pem(cls, s: "str"): """ @@ -37573,6 +37627,19 @@ def from_der(cls, bytes: "bytes"): _UniffiConverterBytes.lower(bytes)) return cls._make_instance_(pointer) + @classmethod + def from_mnemonic(cls, phrase: "str"): + """ + Construct the private key from a mnemonic phrase + """ + + _UniffiConverterString.check_lower(phrase) + + # Call the (fallible) function before creating any half-baked object instances. + pointer = _uniffi_rust_call_with_error(_UniffiConverterTypeSdkFfiError,_UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_secp256k1privatekey_from_mnemonic, + _UniffiConverterString.lower(phrase)) + return cls._make_instance_(pointer) + @classmethod def from_pem(cls, s: "str"): """ @@ -38409,6 +38476,19 @@ def from_der(cls, bytes: "bytes"): _UniffiConverterBytes.lower(bytes)) return cls._make_instance_(pointer) + @classmethod + def from_mnemonic(cls, phrase: "str"): + """ + Construct the private key from a mnemonic phrase + """ + + _UniffiConverterString.check_lower(phrase) + + # Call the (fallible) function before creating any half-baked object instances. + pointer = _uniffi_rust_call_with_error(_UniffiConverterTypeSdkFfiError,_UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_secp256r1privatekey_from_mnemonic, + _UniffiConverterString.lower(phrase)) + return cls._make_instance_(pointer) + @classmethod def from_pem(cls, s: "str"): """ @@ -39266,6 +39346,23 @@ def from_ed25519(cls, keypair: "Ed25519PrivateKey"): _UniffiConverterTypeEd25519PrivateKey.lower(keypair)) return cls._make_instance_(pointer) + @classmethod + def from_mnemonic(cls, phrase: "str",scheme: "SignatureScheme"): + """ + Construct the private key from a mnemonic phrase and the signature + scheme + """ + + _UniffiConverterString.check_lower(phrase) + + _UniffiConverterTypeSignatureScheme.check_lower(scheme) + + # Call the (fallible) function before creating any half-baked object instances. + pointer = _uniffi_rust_call_with_error(_UniffiConverterTypeSdkFfiError,_UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_simplekeypair_from_mnemonic, + _UniffiConverterString.lower(phrase), + _UniffiConverterTypeSignatureScheme.lower(scheme)) + return cls._make_instance_(pointer) + @classmethod def from_pem(cls, s: "str"): """ diff --git a/crates/iota-crypto/Cargo.toml b/crates/iota-crypto/Cargo.toml index b46d1b2b1..a277a2517 100644 --- a/crates/iota-crypto/Cargo.toml +++ b/crates/iota-crypto/Cargo.toml @@ -54,6 +54,7 @@ pem = [ "k256?/pem", ] bls12381 = ["dep:blst", "dep:rand_core", "dep:roaring", "signature/std"] +mnemonic = ["dep:bip32", "dep:slip10_ed25519"] [dependencies] iota-sdk-types = { path = "../iota-sdk-types", default-features = false, features = ["hash", "serde"] } @@ -99,6 +100,10 @@ roaring = { workspace = true, optional = true } # bech32 encoding support bech32 = { version = "0.11.0", optional = true } +# mnemonic support +bip32 = { version = "0.5.3", optional = true } +slip10_ed25519 = { version = "0.1.3", optional = true } + [dev-dependencies] bcs.workspace = true hex.workspace = true diff --git a/crates/iota-crypto/src/ed25519.rs b/crates/iota-crypto/src/ed25519.rs index eb672f4bc..23d51ea65 100644 --- a/crates/iota-crypto/src/ed25519.rs +++ b/crates/iota-crypto/src/ed25519.rs @@ -111,15 +111,17 @@ impl Ed25519PrivateKey { } } -impl crate::PrivateKeyExt for Ed25519PrivateKey { - const SCHEME: SignatureScheme = SignatureScheme::Ed25519; - +impl crate::ToBytes for Ed25519PrivateKey { /// Return the raw 32-byte private key fn to_bytes(&self) -> Vec { self.0.to_bytes().to_vec() } +} - fn from_raw_bytes(bytes: &[u8]) -> Result { +impl crate::FromBytes for Ed25519PrivateKey { + type Error = crate::PrivateKeyError; + + fn from_bytes(bytes: &[u8]) -> Result { if bytes.len() != Self::LENGTH { return Err(crate::PrivateKeyError::InvalidScheme( "invalid ed25519 key length".to_string(), @@ -132,6 +134,30 @@ impl crate::PrivateKeyExt for Ed25519PrivateKey { } } +impl crate::ConstPrivateKeyScheme for Ed25519PrivateKey { + const SCHEME: SignatureScheme = SignatureScheme::Ed25519; +} + +#[cfg(feature = "mnemonic")] +impl crate::FromMnemonic for Ed25519PrivateKey { + type Error = crate::PrivateKeyError; + + fn from_mnemonic(phrase: &str) -> Result { + let mnemonic = bip32::Mnemonic::new(phrase, bip32::Language::English)?; + let seed = mnemonic.to_seed(""); + Ok(Self::new(slip10_ed25519::derive_ed25519_private_key( + seed.as_bytes(), + &[ + crate::DERIVATION_PATH_PURPOSE_ED25519, + crate::DERIVATION_PATH_COIN_TYPE, + 0, + 0, + 0, + ], + ))) + } +} + impl Signer for Ed25519PrivateKey { fn try_sign(&self, msg: &[u8]) -> Result { self.0 diff --git a/crates/iota-crypto/src/lib.rs b/crates/iota-crypto/src/lib.rs index 72527c6bd..8cf995e12 100644 --- a/crates/iota-crypto/src/lib.rs +++ b/crates/iota-crypto/src/lib.rs @@ -23,6 +23,9 @@ pub enum PrivateKeyError { /// HRP (Human Readable Part) error #[error("bech32 HRP error: {0}")] Bech32Hrp(String), + #[cfg(feature = "mnemonic")] + #[error("mnemonic error: {0}")] + Bip32(#[from] bip32::Error), } #[cfg(feature = "bls12381")] @@ -182,23 +185,66 @@ impl> IotaVerifier for T { #[cfg_attr(doc_cfg, doc(cfg(feature = "bech32")))] pub const IOTA_PRIV_KEY_PREFIX: &str = "iotaprivkey"; -/// Extension trait for private key types -pub trait PrivateKeyExt { - /// The signature scheme for this key type +#[cfg(feature = "mnemonic")] +pub const DERIVATION_PATH_COIN_TYPE: u32 = 4218; +#[cfg(feature = "mnemonic")] +pub const DERIVATION_PATH_PURPOSE_ED25519: u32 = 44; +#[cfg(feature = "mnemonic")] +pub const DERIVATION_PATH_PURPOSE_SECP256K1: u32 = 54; +#[cfg(feature = "mnemonic")] +pub const DERIVATION_PATH_PURPOSE_SECP256R1: u32 = 74; + +/// Defines a type which can be converted to bytes +pub trait ToBytes { + /// Returns the raw bytes of this type. + fn to_bytes(&self) -> Vec; +} + +/// Defines a type which can be constructed from bytes +pub trait FromBytes { + type Error; + + /// Create an instance from raw bytes + fn from_bytes(bytes: &[u8]) -> Result + where + Self: Sized; +} + +/// Defines the const scheme of a private key +pub trait ConstPrivateKeyScheme { const SCHEME: iota_sdk_types::SignatureScheme; +} +/// Defines the scheme of a private key +pub trait PrivateKeyScheme { /// Returns the signature scheme for this private key + fn scheme(&self) -> iota_sdk_types::SignatureScheme; +} + +impl PrivateKeyScheme for T { fn scheme(&self) -> iota_sdk_types::SignatureScheme { Self::SCHEME } +} - /// Returns the raw bytes of this private key - fn to_bytes(&self) -> Vec; +/// Defines a type that can be converted to and from flagged bytes, i.e. bytes +/// prepended by some variant indicator flag +pub trait ToFromFlaggedBytes { + type Error; + + /// Returns the bytes with the flag prepended + fn to_flagged_bytes(&self) -> Vec; - /// Creates an instance from raw key bytes (without scheme flag) - fn from_raw_bytes(bytes: &[u8]) -> Result + /// Creates an instance from bytes that include the flag + fn from_flagged_bytes(bytes: &[u8]) -> Result where Self: Sized; +} + +impl + ConstPrivateKeyScheme> ToFromFlaggedBytes + for T +{ + type Error = PrivateKeyError; /// Returns the bytes with signature scheme flag prepended fn to_flagged_bytes(&self) -> Vec { @@ -209,8 +255,7 @@ pub trait PrivateKeyExt { bytes } - /// Creates an instance from bytes that include the signature scheme flag - fn from_flagged_bytes(bytes: &[u8]) -> Result + fn from_flagged_bytes(bytes: &[u8]) -> Result where Self: Sized, { @@ -229,12 +274,30 @@ pub trait PrivateKeyExt { } let key_bytes = &bytes[1..]; - Self::from_raw_bytes(key_bytes) + Self::from_bytes(key_bytes) } +} + +/// Defines a type which can be converted to and from bech32 strings +#[cfg(feature = "bech32")] +pub trait ToFromBech32 { + type Error; /// Encode this private key in Bech32 format with "iotaprivkey" prefix + fn to_bech32(&self) -> Result; + + /// Decode a private key from Bech32 format with "iotaprivkey" prefix + fn from_bech32(value: &str) -> Result + where + Self: Sized; +} + +#[cfg(feature = "bech32")] +impl> ToFromBech32 for T { + type Error = PrivateKeyError; + #[cfg(feature = "bech32")] - fn to_bech32(&self) -> Result { + fn to_bech32(&self) -> Result { use bech32::Hrp; let hrp = Hrp::parse(IOTA_PRIV_KEY_PREFIX) @@ -246,12 +309,8 @@ pub trait PrivateKeyExt { .map_err(|e| PrivateKeyError::Bech32(format!("encoding failed: {e}"))) } - /// Decode a private key from Bech32 format with "iotaprivkey" prefix #[cfg(feature = "bech32")] - fn from_bech32(value: &str) -> Result - where - Self: Sized, - { + fn from_bech32(value: &str) -> Result { use bech32::Hrp; let expected_hrp = Hrp::parse(IOTA_PRIV_KEY_PREFIX) @@ -273,3 +332,14 @@ pub trait PrivateKeyExt { Self::from_flagged_bytes(&data) } } + +/// Defines a type which can be constructed from a mnemonic phrase +#[cfg(feature = "mnemonic")] +pub trait FromMnemonic { + type Error; + + /// Create an instance from a mnemonic phrase + fn from_mnemonic(phrase: &str) -> Result + where + Self: Sized; +} diff --git a/crates/iota-crypto/src/secp256k1.rs b/crates/iota-crypto/src/secp256k1.rs index d2de07e06..e57abfbf6 100644 --- a/crates/iota-crypto/src/secp256k1.rs +++ b/crates/iota-crypto/src/secp256k1.rs @@ -116,14 +116,17 @@ impl Secp256k1PrivateKey { } } -impl crate::PrivateKeyExt for Secp256k1PrivateKey { - const SCHEME: SignatureScheme = SignatureScheme::Secp256k1; - +impl crate::ToBytes for Secp256k1PrivateKey { + /// Return the raw 32-byte private key fn to_bytes(&self) -> Vec { self.0.to_bytes().to_vec() } +} + +impl crate::FromBytes for Secp256k1PrivateKey { + type Error = crate::PrivateKeyError; - fn from_raw_bytes(bytes: &[u8]) -> Result { + fn from_bytes(bytes: &[u8]) -> Result { if bytes.len() != Self::LENGTH { return Err(crate::PrivateKeyError::InvalidScheme( "invalid secp256k1 key length".to_string(), @@ -136,6 +139,31 @@ impl crate::PrivateKeyExt for Secp256k1PrivateKey { } } +impl crate::ConstPrivateKeyScheme for Secp256k1PrivateKey { + const SCHEME: SignatureScheme = SignatureScheme::Secp256k1; +} + +#[cfg(feature = "mnemonic")] +impl crate::FromMnemonic for Secp256k1PrivateKey { + type Error = crate::PrivateKeyError; + + fn from_mnemonic(phrase: &str) -> Result { + use std::str::FromStr; + + use crate::FromBytes; + + let mnemonic = bip32::Mnemonic::new(phrase, bip32::Language::English)?; + let seed = mnemonic.to_seed(""); + let path = bip32::DerivationPath::from_str(&format!( + "m/{}'/{}'/0'/0'/0'", + crate::DERIVATION_PATH_PURPOSE_SECP256K1, + crate::DERIVATION_PATH_COIN_TYPE + ))?; + let child_xprv = bip32::XPrv::derive_from_path(seed, &path)?; + Ok(Self::from_bytes(&child_xprv.private_key().to_bytes())?) + } +} + impl Signer for Secp256k1PrivateKey { fn try_sign(&self, message: &[u8]) -> Result { let signature: k256::ecdsa::Signature = self.0.try_sign(message)?; diff --git a/crates/iota-crypto/src/secp256r1.rs b/crates/iota-crypto/src/secp256r1.rs index 6eac52bd9..03955296c 100644 --- a/crates/iota-crypto/src/secp256r1.rs +++ b/crates/iota-crypto/src/secp256r1.rs @@ -116,14 +116,17 @@ impl Secp256r1PrivateKey { } } -impl crate::PrivateKeyExt for Secp256r1PrivateKey { - const SCHEME: SignatureScheme = SignatureScheme::Secp256r1; - +impl crate::ToBytes for Secp256r1PrivateKey { + /// Return the raw 32-byte private key fn to_bytes(&self) -> Vec { self.0.to_bytes().to_vec() } +} + +impl crate::FromBytes for Secp256r1PrivateKey { + type Error = crate::PrivateKeyError; - fn from_raw_bytes(bytes: &[u8]) -> Result { + fn from_bytes(bytes: &[u8]) -> Result { if bytes.len() != Self::LENGTH { return Err(crate::PrivateKeyError::InvalidScheme( "invalid secp256r1 key length".to_string(), @@ -136,6 +139,31 @@ impl crate::PrivateKeyExt for Secp256r1PrivateKey { } } +impl crate::ConstPrivateKeyScheme for Secp256r1PrivateKey { + const SCHEME: SignatureScheme = SignatureScheme::Secp256r1; +} + +#[cfg(feature = "mnemonic")] +impl crate::FromMnemonic for Secp256r1PrivateKey { + type Error = crate::PrivateKeyError; + + fn from_mnemonic(phrase: &str) -> Result { + use std::str::FromStr; + + use crate::FromBytes; + + let mnemonic = bip32::Mnemonic::new(phrase, bip32::Language::English)?; + let seed = mnemonic.to_seed(""); + let path = bip32::DerivationPath::from_str(&format!( + "m/{}'/{}'/0'/0'/0'", + crate::DERIVATION_PATH_PURPOSE_SECP256R1, + crate::DERIVATION_PATH_COIN_TYPE + ))?; + let child_xprv = bip32::XPrv::derive_from_path(seed, &path)?; + Ok(Self::from_bytes(&child_xprv.private_key().to_bytes())?) + } +} + impl Signer for Secp256r1PrivateKey { fn try_sign(&self, message: &[u8]) -> Result { let signature: p256::ecdsa::Signature = self.0.try_sign(message)?; diff --git a/crates/iota-crypto/src/simple.rs b/crates/iota-crypto/src/simple.rs index 12ba37c78..de198c144 100644 --- a/crates/iota-crypto/src/simple.rs +++ b/crates/iota-crypto/src/simple.rs @@ -82,7 +82,7 @@ mod keypair { }; use signature::{Signer, Verifier}; - use crate::{PrivateKeyExt, SignatureError}; + use crate::SignatureError; #[derive(Debug, Clone)] pub struct SimpleKeypair { @@ -138,6 +138,8 @@ mod keypair { /// Encode a SimpleKeypair as `flag || privkey` in bytes pub fn to_bytes(&self) -> Vec { + use crate::ToBytes; + let mut bytes = Vec::new(); bytes.push(self.scheme().to_u8()); @@ -296,6 +298,63 @@ mod keypair { InnerKeypair::Secp256r1(private_key) => private_key.to_pem(), } } + + /// Decode a private key from Bech32 format with "iotaprivkey" prefix + #[cfg(feature = "bech32")] + pub fn from_bech32(value: &str) -> Result + where + Self: Sized, + { + use bech32::Hrp; + + let expected_hrp = Hrp::parse(crate::IOTA_PRIV_KEY_PREFIX) + .map_err(|e| crate::PrivateKeyError::Bech32Hrp(format!("{e}")))?; + + let (hrp, data) = bech32::decode(value) + .map_err(|e| crate::PrivateKeyError::Bech32(format!("decoding failed: {e}")))?; + + if hrp != expected_hrp { + return Err(crate::PrivateKeyError::Bech32Hrp(format!( + "expected {}, got {hrp}", + crate::IOTA_PRIV_KEY_PREFIX + ))); + } + + if data.is_empty() { + return Err(crate::PrivateKeyError::EmptyData("bech32 data".to_string())); + } + + Self::from_bytes(&data) + .map_err(|e| crate::PrivateKeyError::InvalidScheme(e.to_string())) + } + + #[cfg(feature = "mnemonic")] + pub fn from_mnemonic( + phrase: &str, + scheme: SignatureScheme, + ) -> Result { + use crate::FromMnemonic; + + Ok(match scheme { + #[cfg(feature = "ed25519")] + SignatureScheme::Ed25519 => { + crate::ed25519::Ed25519PrivateKey::from_mnemonic(phrase)?.into() + } + #[cfg(feature = "secp256k1")] + SignatureScheme::Secp256k1 => { + crate::secp256k1::Secp256k1PrivateKey::from_mnemonic(phrase)?.into() + } + #[cfg(feature = "secp256r1")] + SignatureScheme::Secp256r1 => { + crate::secp256r1::Secp256r1PrivateKey::from_mnemonic(phrase)?.into() + } + _ => { + return Err(crate::PrivateKeyError::InvalidScheme(format!( + "scheme not supported for derivation from mnemonic: {scheme}" + ))); + } + }) + } } impl Signer for SimpleKeypair { @@ -538,15 +597,7 @@ mod keypair { } } - impl crate::PrivateKeyExt for SimpleKeypair { - // SimpleKeypair doesn't have a single scheme since it can contain any scheme - // We provide a dummy value since we override all methods - const SCHEME: SignatureScheme = SignatureScheme::Ed25519; - - fn scheme(&self) -> SignatureScheme { - self.scheme() - } - + impl crate::ToBytes for SimpleKeypair { fn to_bytes(&self) -> Vec { // For SimpleKeypair, to_bytes() already returns flagged bytes // We need the raw key bytes without the flag for the trait @@ -559,16 +610,25 @@ mod keypair { InnerKeypair::Secp256r1(private_key) => private_key.to_bytes().as_slice().to_vec(), } } + } + + impl crate::PrivateKeyScheme for SimpleKeypair { + fn scheme(&self) -> iota_sdk_types::SignatureScheme { + self.scheme() + } + } + + impl crate::ToFromFlaggedBytes for SimpleKeypair { + type Error = crate::PrivateKeyError; - fn from_raw_bytes(_bytes: &[u8]) -> Result { - // SimpleKeypair can't be created from raw bytes without knowing the scheme - // This should not be called since SimpleKeypair overrides from_flagged_bytes - Err(crate::PrivateKeyError::InvalidScheme( - "SimpleKeypair should use from_bytes instead".to_string(), - )) + fn to_flagged_bytes(&self) -> Vec { + self.to_bytes() } - fn from_flagged_bytes(bytes: &[u8]) -> Result { + fn from_flagged_bytes(bytes: &[u8]) -> Result + where + Self: Sized, + { Self::from_bytes(bytes) .map_err(|e| crate::PrivateKeyError::InvalidScheme(e.to_string())) } @@ -581,7 +641,7 @@ mod tests { use super::*; use crate::{ - PrivateKeyExt, + ToFromBech32, ed25519::{Ed25519PrivateKey, Ed25519VerifyingKey}, secp256k1::{Secp256k1PrivateKey, Secp256k1VerifyingKey}, secp256r1::{Secp256r1PrivateKey, Secp256r1VerifyingKey}, diff --git a/crates/iota-sdk-ffi/Cargo.toml b/crates/iota-sdk-ffi/Cargo.toml index 60a731188..1ea88573a 100644 --- a/crates/iota-sdk-ffi/Cargo.toml +++ b/crates/iota-sdk-ffi/Cargo.toml @@ -27,7 +27,7 @@ serde_json.workspace = true tokio = { workspace = true, features = ["time"] } uniffi = { version = "0.29", features = ["cli", "tokio"] } -iota-crypto = { path = "../iota-crypto", features = ["bls12381", "ed25519", "secp256r1", "passkey", "secp256k1", "zklogin", "pem", "bech32"] } +iota-crypto = { path = "../iota-crypto", features = ["bls12381", "ed25519", "secp256r1", "passkey", "secp256k1", "zklogin", "pem", "bech32", "mnemonic"] } iota-graphql-client = { path = "../iota-graphql-client" } iota-transaction-builder = { path = "../iota-transaction-builder" } iota-types = { package = "iota-sdk-types", path = "../iota-sdk-types", features = ["hash", "rand"] } diff --git a/crates/iota-sdk-ffi/src/crypto/ed25519.rs b/crates/iota-sdk-ffi/src/crypto/ed25519.rs index 157fb18d6..da27404c5 100644 --- a/crates/iota-sdk-ffi/src/crypto/ed25519.rs +++ b/crates/iota-sdk-ffi/src/crypto/ed25519.rs @@ -1,7 +1,7 @@ // Copyright (c) 2025 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use iota_crypto::PrivateKeyExt; +use iota_crypto::{FromMnemonic, ToBytes, ToFromBech32}; use iota_types::SignatureScheme; use rand::rngs::OsRng; @@ -85,6 +85,12 @@ impl Ed25519PrivateKey { Ok(iota_crypto::ed25519::Ed25519PrivateKey::from_bech32(value)?.into()) } + /// Construct the private key from a mnemonic phrase + #[uniffi::constructor] + pub fn from_mnemonic(phrase: &str) -> Result { + Ok(iota_crypto::ed25519::Ed25519PrivateKey::from_mnemonic(phrase)?.into()) + } + pub fn try_sign(&self, message: &[u8]) -> Result { Ok(iota_crypto::Signer::::try_sign(&self.0, message)?.into()) } diff --git a/crates/iota-sdk-ffi/src/crypto/secp256k1.rs b/crates/iota-sdk-ffi/src/crypto/secp256k1.rs index fe82bde4e..a8199e9c1 100644 --- a/crates/iota-sdk-ffi/src/crypto/secp256k1.rs +++ b/crates/iota-sdk-ffi/src/crypto/secp256k1.rs @@ -1,7 +1,7 @@ // Copyright (c) 2025 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use iota_crypto::PrivateKeyExt; +use iota_crypto::{FromMnemonic, ToBytes, ToFromBech32}; use iota_types::SignatureScheme; use rand::rngs::OsRng; @@ -85,6 +85,12 @@ impl Secp256k1PrivateKey { Ok(iota_crypto::secp256k1::Secp256k1PrivateKey::from_bech32(value)?.into()) } + /// Construct the private key from a mnemonic phrase + #[uniffi::constructor] + pub fn from_mnemonic(phrase: &str) -> Result { + Ok(iota_crypto::secp256k1::Secp256k1PrivateKey::from_mnemonic(phrase)?.into()) + } + pub fn try_sign(&self, message: &[u8]) -> Result { Ok( iota_crypto::Signer::::try_sign(&self.0, message)? diff --git a/crates/iota-sdk-ffi/src/crypto/secp256r1.rs b/crates/iota-sdk-ffi/src/crypto/secp256r1.rs index d96bb9db0..88c84bee8 100644 --- a/crates/iota-sdk-ffi/src/crypto/secp256r1.rs +++ b/crates/iota-sdk-ffi/src/crypto/secp256r1.rs @@ -3,7 +3,7 @@ use std::sync::Arc; -use iota_crypto::{PrivateKeyExt, Signer, Verifier}; +use iota_crypto::{FromMnemonic, Signer, ToBytes, ToFromBech32, Verifier}; use iota_types::SignatureScheme; use rand::rngs::OsRng; @@ -106,6 +106,12 @@ impl Secp256r1PrivateKey { pub fn from_bech32(value: &str) -> Result { Ok(iota_crypto::secp256r1::Secp256r1PrivateKey::from_bech32(value)?.into()) } + + /// Construct the private key from a mnemonic phrase + #[uniffi::constructor] + pub fn from_mnemonic(phrase: &str) -> Result { + Ok(iota_crypto::secp256r1::Secp256r1PrivateKey::from_mnemonic(phrase)?.into()) + } } #[derive(derive_more::From, uniffi::Object)] diff --git a/crates/iota-sdk-ffi/src/crypto/simple.rs b/crates/iota-sdk-ffi/src/crypto/simple.rs index 49be36417..f533de8b1 100644 --- a/crates/iota-sdk-ffi/src/crypto/simple.rs +++ b/crates/iota-sdk-ffi/src/crypto/simple.rs @@ -1,7 +1,7 @@ // Copyright (c) 2025 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use iota_crypto::{PrivateKeyExt, Signer, Verifier}; +use iota_crypto::{Signer, ToBytes, ToFromBech32, Verifier}; use iota_types::SignatureScheme; use crate::{ @@ -112,6 +112,13 @@ impl SimpleKeypair { Ok(self.0.to_pem()?) } + /// Construct the private key from a mnemonic phrase and the signature + /// scheme + #[uniffi::constructor] + pub fn from_mnemonic(phrase: &str, scheme: SignatureScheme) -> Result { + Ok(iota_crypto::simple::SimpleKeypair::from_mnemonic(phrase, scheme)?.into()) + } + fn try_sign(&self, message: &[u8]) -> Result { Ok(Signer::::try_sign(&self.0, message)?.into()) } diff --git a/crates/iota-sdk-types/src/crypto/signature.rs b/crates/iota-sdk-types/src/crypto/signature.rs index d1dc67fac..620f364c4 100644 --- a/crates/iota-sdk-types/src/crypto/signature.rs +++ b/crates/iota-sdk-types/src/crypto/signature.rs @@ -212,16 +212,23 @@ impl SimpleSignature { /// zklogin-flag = %x05 /// passkey-flag = %x06 /// ``` -#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, derive_more::Display)] #[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))] #[repr(u8)] pub enum SignatureScheme { + #[display("ed25519")] Ed25519 = 0x00, + #[display("secp256k1")] Secp256k1 = 0x01, + #[display("secp256r1")] Secp256r1 = 0x02, + #[display("multisig")] Multisig = 0x03, + #[display("bls12381")] Bls12381 = 0x04, // This is currently not supported for user addresses + #[display("zklogin")] ZkLogin = 0x05, + #[display("passkey")] Passkey = 0x06, } @@ -230,19 +237,6 @@ impl SignatureScheme { Ed25519, Secp256k1, Secp256r1, Multisig, Bls12381, ZkLogin, Passkey, ); - /// Return the name of this signature scheme - pub fn name(self) -> &'static str { - match self { - SignatureScheme::Ed25519 => "ed25519", - SignatureScheme::Secp256k1 => "secp256k1", - SignatureScheme::Secp256r1 => "secp256r1", - SignatureScheme::Multisig => "multisig", - SignatureScheme::Bls12381 => "bls12381", - SignatureScheme::ZkLogin => "zklogin", - SignatureScheme::Passkey => "passkey", - } - } - /// Try constructing from a byte flag pub fn from_byte(flag: u8) -> Result { match flag { diff --git a/crates/iota-sdk/Cargo.toml b/crates/iota-sdk/Cargo.toml index 4a955930f..634dc5460 100644 --- a/crates/iota-sdk/Cargo.toml +++ b/crates/iota-sdk/Cargo.toml @@ -16,6 +16,8 @@ default = [ "zklogin", "pem", "bls12381", + "bech32", + "mnemonic", "graphql", "txn-builder", "types", @@ -35,6 +37,8 @@ secp256k1 = ["crypto", "iota-crypto/secp256k1"] zklogin = ["crypto", "iota-crypto/zklogin"] pem = ["crypto", "iota-crypto/pem"] bls12381 = ["crypto", "iota-crypto/bls12381"] +bech32 = ["crypto", "iota-crypto/bech32"] +mnemonic = ["crypto", "iota-crypto/mnemonic"] # GraphQL graphql = ["dep:iota-graphql-client"] diff --git a/crates/iota-sdk/examples/generate_ed25519_address.rs b/crates/iota-sdk/examples/generate_ed25519_address.rs index aa9337d2b..0bc247fe9 100644 --- a/crates/iota-sdk/examples/generate_ed25519_address.rs +++ b/crates/iota-sdk/examples/generate_ed25519_address.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use base64ct::{Base64, Encoding}; -use iota_crypto::{PrivateKeyExt, ed25519::Ed25519PrivateKey}; +use iota_crypto::{ToFromBech32, ed25519::Ed25519PrivateKey}; use iota_types::PublicKeyExt; use rand::rngs::OsRng; From 665d9aa5f47f70e70b0ea9fdd808dbfa62d3edc7 Mon Sep 17 00:00:00 2001 From: Chloe Martin Date: Mon, 27 Oct 2025 16:20:59 +0100 Subject: [PATCH 02/12] clippy --- crates/iota-crypto/src/secp256k1.rs | 2 +- crates/iota-crypto/src/secp256r1.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/iota-crypto/src/secp256k1.rs b/crates/iota-crypto/src/secp256k1.rs index e57abfbf6..e4c99d23d 100644 --- a/crates/iota-crypto/src/secp256k1.rs +++ b/crates/iota-crypto/src/secp256k1.rs @@ -160,7 +160,7 @@ impl crate::FromMnemonic for Secp256k1PrivateKey { crate::DERIVATION_PATH_COIN_TYPE ))?; let child_xprv = bip32::XPrv::derive_from_path(seed, &path)?; - Ok(Self::from_bytes(&child_xprv.private_key().to_bytes())?) + Self::from_bytes(&child_xprv.private_key().to_bytes()) } } diff --git a/crates/iota-crypto/src/secp256r1.rs b/crates/iota-crypto/src/secp256r1.rs index 03955296c..6db7d8aaa 100644 --- a/crates/iota-crypto/src/secp256r1.rs +++ b/crates/iota-crypto/src/secp256r1.rs @@ -160,7 +160,7 @@ impl crate::FromMnemonic for Secp256r1PrivateKey { crate::DERIVATION_PATH_COIN_TYPE ))?; let child_xprv = bip32::XPrv::derive_from_path(seed, &path)?; - Ok(Self::from_bytes(&child_xprv.private_key().to_bytes())?) + Self::from_bytes(&child_xprv.private_key().to_bytes()) } } From dd56e068e99ded3aad4ad4666316ff286096b16c Mon Sep 17 00:00:00 2001 From: Chloe Martin Date: Tue, 28 Oct 2025 09:29:20 +0100 Subject: [PATCH 03/12] allow passing password and path --- crates/iota-crypto/src/ed25519.rs | 28 ++++++++++++++------- crates/iota-crypto/src/lib.rs | 6 ++++- crates/iota-crypto/src/secp256k1.rs | 22 ++++++++++------ crates/iota-crypto/src/secp256r1.rs | 23 +++++++++++------ crates/iota-crypto/src/simple.rs | 12 ++++++--- crates/iota-sdk-ffi/src/crypto/ed25519.rs | 15 ++++++++--- crates/iota-sdk-ffi/src/crypto/secp256k1.rs | 15 ++++++++--- crates/iota-sdk-ffi/src/crypto/secp256r1.rs | 15 ++++++++--- crates/iota-sdk-ffi/src/crypto/simple.rs | 17 ++++++++++--- 9 files changed, 113 insertions(+), 40 deletions(-) diff --git a/crates/iota-crypto/src/ed25519.rs b/crates/iota-crypto/src/ed25519.rs index 23d51ea65..efac08e51 100644 --- a/crates/iota-crypto/src/ed25519.rs +++ b/crates/iota-crypto/src/ed25519.rs @@ -142,18 +142,28 @@ impl crate::ConstPrivateKeyScheme for Ed25519PrivateKey { impl crate::FromMnemonic for Ed25519PrivateKey { type Error = crate::PrivateKeyError; - fn from_mnemonic(phrase: &str) -> Result { + fn from_mnemonic( + phrase: &str, + password: impl Into>, + path: impl Into>, + ) -> Result { let mnemonic = bip32::Mnemonic::new(phrase, bip32::Language::English)?; - let seed = mnemonic.to_seed(""); + let seed = mnemonic.to_seed(&password.into().unwrap_or_default()); + let path = path + .into() + .map(|p| p.as_ref().into_iter().map(|c| c.0).collect()) + .unwrap_or_else(|| { + vec![ + crate::DERIVATION_PATH_PURPOSE_ED25519, + crate::DERIVATION_PATH_COIN_TYPE, + 0, + 0, + 0, + ] + }); Ok(Self::new(slip10_ed25519::derive_ed25519_private_key( seed.as_bytes(), - &[ - crate::DERIVATION_PATH_PURPOSE_ED25519, - crate::DERIVATION_PATH_COIN_TYPE, - 0, - 0, - 0, - ], + &path, ))) } } diff --git a/crates/iota-crypto/src/lib.rs b/crates/iota-crypto/src/lib.rs index 8cf995e12..911416bf3 100644 --- a/crates/iota-crypto/src/lib.rs +++ b/crates/iota-crypto/src/lib.rs @@ -339,7 +339,11 @@ pub trait FromMnemonic { type Error; /// Create an instance from a mnemonic phrase - fn from_mnemonic(phrase: &str) -> Result + fn from_mnemonic( + phrase: &str, + password: impl Into>, + path: impl Into>, + ) -> Result where Self: Sized; } diff --git a/crates/iota-crypto/src/secp256k1.rs b/crates/iota-crypto/src/secp256k1.rs index e4c99d23d..42e573e57 100644 --- a/crates/iota-crypto/src/secp256k1.rs +++ b/crates/iota-crypto/src/secp256k1.rs @@ -147,18 +147,26 @@ impl crate::ConstPrivateKeyScheme for Secp256k1PrivateKey { impl crate::FromMnemonic for Secp256k1PrivateKey { type Error = crate::PrivateKeyError; - fn from_mnemonic(phrase: &str) -> Result { + fn from_mnemonic( + phrase: &str, + password: impl Into>, + path: impl Into>, + ) -> Result { use std::str::FromStr; use crate::FromBytes; let mnemonic = bip32::Mnemonic::new(phrase, bip32::Language::English)?; - let seed = mnemonic.to_seed(""); - let path = bip32::DerivationPath::from_str(&format!( - "m/{}'/{}'/0'/0'/0'", - crate::DERIVATION_PATH_PURPOSE_SECP256K1, - crate::DERIVATION_PATH_COIN_TYPE - ))?; + let seed = mnemonic.to_seed(&password.into().unwrap_or_default()); + let path = if let Some(path) = path.into() { + path + } else { + bip32::DerivationPath::from_str(&format!( + "m/{}'/{}'/0'/0'/0'", + crate::DERIVATION_PATH_PURPOSE_SECP256K1, + crate::DERIVATION_PATH_COIN_TYPE + ))? + }; let child_xprv = bip32::XPrv::derive_from_path(seed, &path)?; Self::from_bytes(&child_xprv.private_key().to_bytes()) } diff --git a/crates/iota-crypto/src/secp256r1.rs b/crates/iota-crypto/src/secp256r1.rs index 6db7d8aaa..2c530531e 100644 --- a/crates/iota-crypto/src/secp256r1.rs +++ b/crates/iota-crypto/src/secp256r1.rs @@ -147,18 +147,27 @@ impl crate::ConstPrivateKeyScheme for Secp256r1PrivateKey { impl crate::FromMnemonic for Secp256r1PrivateKey { type Error = crate::PrivateKeyError; - fn from_mnemonic(phrase: &str) -> Result { + fn from_mnemonic( + phrase: &str, + password: impl Into>, + path: impl Into>, + ) -> Result { use std::str::FromStr; use crate::FromBytes; let mnemonic = bip32::Mnemonic::new(phrase, bip32::Language::English)?; - let seed = mnemonic.to_seed(""); - let path = bip32::DerivationPath::from_str(&format!( - "m/{}'/{}'/0'/0'/0'", - crate::DERIVATION_PATH_PURPOSE_SECP256R1, - crate::DERIVATION_PATH_COIN_TYPE - ))?; + let seed = mnemonic.to_seed(&password.into().unwrap_or_default()); + + let path = if let Some(path) = path.into() { + path + } else { + bip32::DerivationPath::from_str(&format!( + "m/{}'/{}'/0'/0'/0'", + crate::DERIVATION_PATH_PURPOSE_SECP256R1, + crate::DERIVATION_PATH_COIN_TYPE + ))? + }; let child_xprv = bip32::XPrv::derive_from_path(seed, &path)?; Self::from_bytes(&child_xprv.private_key().to_bytes()) } diff --git a/crates/iota-crypto/src/simple.rs b/crates/iota-crypto/src/simple.rs index de198c144..d408cd6ca 100644 --- a/crates/iota-crypto/src/simple.rs +++ b/crates/iota-crypto/src/simple.rs @@ -330,23 +330,27 @@ mod keypair { #[cfg(feature = "mnemonic")] pub fn from_mnemonic( - phrase: &str, scheme: SignatureScheme, + phrase: &str, + password: impl Into>, + path: impl Into>, ) -> Result { use crate::FromMnemonic; Ok(match scheme { #[cfg(feature = "ed25519")] SignatureScheme::Ed25519 => { - crate::ed25519::Ed25519PrivateKey::from_mnemonic(phrase)?.into() + crate::ed25519::Ed25519PrivateKey::from_mnemonic(phrase, password, path)?.into() } #[cfg(feature = "secp256k1")] SignatureScheme::Secp256k1 => { - crate::secp256k1::Secp256k1PrivateKey::from_mnemonic(phrase)?.into() + crate::secp256k1::Secp256k1PrivateKey::from_mnemonic(phrase, password, path)? + .into() } #[cfg(feature = "secp256r1")] SignatureScheme::Secp256r1 => { - crate::secp256r1::Secp256r1PrivateKey::from_mnemonic(phrase)?.into() + crate::secp256r1::Secp256r1PrivateKey::from_mnemonic(phrase, password, path)? + .into() } _ => { return Err(crate::PrivateKeyError::InvalidScheme(format!( diff --git a/crates/iota-sdk-ffi/src/crypto/ed25519.rs b/crates/iota-sdk-ffi/src/crypto/ed25519.rs index da27404c5..1d9b22a00 100644 --- a/crates/iota-sdk-ffi/src/crypto/ed25519.rs +++ b/crates/iota-sdk-ffi/src/crypto/ed25519.rs @@ -86,9 +86,18 @@ impl Ed25519PrivateKey { } /// Construct the private key from a mnemonic phrase - #[uniffi::constructor] - pub fn from_mnemonic(phrase: &str) -> Result { - Ok(iota_crypto::ed25519::Ed25519PrivateKey::from_mnemonic(phrase)?.into()) + #[uniffi::constructor(default(password = None, path = None))] + pub fn from_mnemonic( + phrase: &str, + password: Option, + path: Option, + ) -> Result { + Ok(iota_crypto::ed25519::Ed25519PrivateKey::from_mnemonic( + phrase, + password, + path.map(|p| p.parse()).transpose()?, + )? + .into()) } pub fn try_sign(&self, message: &[u8]) -> Result { diff --git a/crates/iota-sdk-ffi/src/crypto/secp256k1.rs b/crates/iota-sdk-ffi/src/crypto/secp256k1.rs index a8199e9c1..6be9aed59 100644 --- a/crates/iota-sdk-ffi/src/crypto/secp256k1.rs +++ b/crates/iota-sdk-ffi/src/crypto/secp256k1.rs @@ -86,9 +86,18 @@ impl Secp256k1PrivateKey { } /// Construct the private key from a mnemonic phrase - #[uniffi::constructor] - pub fn from_mnemonic(phrase: &str) -> Result { - Ok(iota_crypto::secp256k1::Secp256k1PrivateKey::from_mnemonic(phrase)?.into()) + #[uniffi::constructor(default(password = None, path = None))] + pub fn from_mnemonic( + phrase: &str, + password: Option, + path: Option, + ) -> Result { + Ok(iota_crypto::secp256k1::Secp256k1PrivateKey::from_mnemonic( + phrase, + password, + path.map(|p| p.parse()).transpose()?, + )? + .into()) } pub fn try_sign(&self, message: &[u8]) -> Result { diff --git a/crates/iota-sdk-ffi/src/crypto/secp256r1.rs b/crates/iota-sdk-ffi/src/crypto/secp256r1.rs index 88c84bee8..18b005765 100644 --- a/crates/iota-sdk-ffi/src/crypto/secp256r1.rs +++ b/crates/iota-sdk-ffi/src/crypto/secp256r1.rs @@ -108,9 +108,18 @@ impl Secp256r1PrivateKey { } /// Construct the private key from a mnemonic phrase - #[uniffi::constructor] - pub fn from_mnemonic(phrase: &str) -> Result { - Ok(iota_crypto::secp256r1::Secp256r1PrivateKey::from_mnemonic(phrase)?.into()) + #[uniffi::constructor(default(password = None, path = None))] + pub fn from_mnemonic( + phrase: &str, + password: Option, + path: Option, + ) -> Result { + Ok(iota_crypto::secp256r1::Secp256r1PrivateKey::from_mnemonic( + phrase, + password, + path.map(|p| p.parse()).transpose()?, + )? + .into()) } } diff --git a/crates/iota-sdk-ffi/src/crypto/simple.rs b/crates/iota-sdk-ffi/src/crypto/simple.rs index f533de8b1..e7d9f9c99 100644 --- a/crates/iota-sdk-ffi/src/crypto/simple.rs +++ b/crates/iota-sdk-ffi/src/crypto/simple.rs @@ -114,9 +114,20 @@ impl SimpleKeypair { /// Construct the private key from a mnemonic phrase and the signature /// scheme - #[uniffi::constructor] - pub fn from_mnemonic(phrase: &str, scheme: SignatureScheme) -> Result { - Ok(iota_crypto::simple::SimpleKeypair::from_mnemonic(phrase, scheme)?.into()) + #[uniffi::constructor(default(password = None, path = None))] + pub fn from_mnemonic( + scheme: SignatureScheme, + phrase: &str, + password: Option, + path: Option, + ) -> Result { + Ok(iota_crypto::simple::SimpleKeypair::from_mnemonic( + scheme, + phrase, + password, + path.map(|p| p.parse()).transpose()?, + )? + .into()) } fn try_sign(&self, message: &[u8]) -> Result { From a44ca837f42bdcd5c46a7f7c568bb84f6f21ea7d Mon Sep 17 00:00:00 2001 From: Chloe Martin Date: Tue, 28 Oct 2025 10:57:05 +0100 Subject: [PATCH 04/12] fix mnemonic parsing and add example --- crates/iota-crypto/Cargo.toml | 3 +- crates/iota-crypto/src/ed25519.rs | 32 ++++++------ crates/iota-crypto/src/lib.rs | 5 +- crates/iota-crypto/src/secp256k1.rs | 17 +++---- crates/iota-crypto/src/secp256r1.rs | 17 +++---- crates/iota-crypto/src/simple.rs | 2 +- crates/iota-sdk-ffi/src/crypto/ed25519.rs | 7 +-- crates/iota-sdk-ffi/src/crypto/secp256k1.rs | 10 ++-- crates/iota-sdk-ffi/src/crypto/secp256r1.rs | 10 ++-- crates/iota-sdk-ffi/src/crypto/simple.rs | 11 ++-- .../examples/address_from_mnemonic.rs | 51 +++++++++++++++++++ 11 files changed, 103 insertions(+), 62 deletions(-) create mode 100644 crates/iota-sdk/examples/address_from_mnemonic.rs diff --git a/crates/iota-crypto/Cargo.toml b/crates/iota-crypto/Cargo.toml index a277a2517..375202ad5 100644 --- a/crates/iota-crypto/Cargo.toml +++ b/crates/iota-crypto/Cargo.toml @@ -54,7 +54,7 @@ pem = [ "k256?/pem", ] bls12381 = ["dep:blst", "dep:rand_core", "dep:roaring", "signature/std"] -mnemonic = ["dep:bip32", "dep:slip10_ed25519"] +mnemonic = ["dep:bip32", "dep:bip39", "dep:slip10_ed25519"] [dependencies] iota-sdk-types = { path = "../iota-sdk-types", default-features = false, features = ["hash", "serde"] } @@ -102,6 +102,7 @@ bech32 = { version = "0.11.0", optional = true } # mnemonic support bip32 = { version = "0.5.3", optional = true } +bip39 = { version = "2.0.0", optional = true } slip10_ed25519 = { version = "0.1.3", optional = true } [dev-dependencies] diff --git a/crates/iota-crypto/src/ed25519.rs b/crates/iota-crypto/src/ed25519.rs index efac08e51..c3fc36962 100644 --- a/crates/iota-crypto/src/ed25519.rs +++ b/crates/iota-crypto/src/ed25519.rs @@ -145,25 +145,25 @@ impl crate::FromMnemonic for Ed25519PrivateKey { fn from_mnemonic( phrase: &str, password: impl Into>, - path: impl Into>, + path: impl Into>, ) -> Result { - let mnemonic = bip32::Mnemonic::new(phrase, bip32::Language::English)?; + use std::str::FromStr; + + let mnemonic = bip39::Mnemonic::parse_in_normalized(bip39::Language::English, phrase)?; let seed = mnemonic.to_seed(&password.into().unwrap_or_default()); - let path = path - .into() - .map(|p| p.as_ref().into_iter().map(|c| c.0).collect()) - .unwrap_or_else(|| { - vec![ - crate::DERIVATION_PATH_PURPOSE_ED25519, - crate::DERIVATION_PATH_COIN_TYPE, - 0, - 0, - 0, - ] - }); + let path = path.into().unwrap_or_else(|| { + format!( + "m/{}'/{}'/0'/0'/0'", + crate::DERIVATION_PATH_PURPOSE_ED25519, + crate::DERIVATION_PATH_COIN_TYPE + ) + }); + let path = bip32::DerivationPath::from_str(&path)? + .into_iter() + .map(|c| c.0) + .collect::>(); Ok(Self::new(slip10_ed25519::derive_ed25519_private_key( - seed.as_bytes(), - &path, + &seed, &path, ))) } } diff --git a/crates/iota-crypto/src/lib.rs b/crates/iota-crypto/src/lib.rs index 911416bf3..2f2bd9207 100644 --- a/crates/iota-crypto/src/lib.rs +++ b/crates/iota-crypto/src/lib.rs @@ -26,6 +26,9 @@ pub enum PrivateKeyError { #[cfg(feature = "mnemonic")] #[error("mnemonic error: {0}")] Bip32(#[from] bip32::Error), + #[cfg(feature = "mnemonic")] + #[error("mnemonic error: {0}")] + Bip39(#[from] bip39::Error), } #[cfg(feature = "bls12381")] @@ -342,7 +345,7 @@ pub trait FromMnemonic { fn from_mnemonic( phrase: &str, password: impl Into>, - path: impl Into>, + path: impl Into>, ) -> Result where Self: Sized; diff --git a/crates/iota-crypto/src/secp256k1.rs b/crates/iota-crypto/src/secp256k1.rs index 42e573e57..3342511fc 100644 --- a/crates/iota-crypto/src/secp256k1.rs +++ b/crates/iota-crypto/src/secp256k1.rs @@ -150,24 +150,23 @@ impl crate::FromMnemonic for Secp256k1PrivateKey { fn from_mnemonic( phrase: &str, password: impl Into>, - path: impl Into>, + path: impl Into>, ) -> Result { use std::str::FromStr; use crate::FromBytes; - let mnemonic = bip32::Mnemonic::new(phrase, bip32::Language::English)?; + let mnemonic = bip39::Mnemonic::parse_in_normalized(bip39::Language::English, phrase)?; let seed = mnemonic.to_seed(&password.into().unwrap_or_default()); - let path = if let Some(path) = path.into() { - path - } else { - bip32::DerivationPath::from_str(&format!( + let path = path.into().unwrap_or_else(|| { + format!( "m/{}'/{}'/0'/0'/0'", crate::DERIVATION_PATH_PURPOSE_SECP256K1, crate::DERIVATION_PATH_COIN_TYPE - ))? - }; - let child_xprv = bip32::XPrv::derive_from_path(seed, &path)?; + ) + }); + let child_xprv = + bip32::XPrv::derive_from_path(seed, &bip32::DerivationPath::from_str(&path)?)?; Self::from_bytes(&child_xprv.private_key().to_bytes()) } } diff --git a/crates/iota-crypto/src/secp256r1.rs b/crates/iota-crypto/src/secp256r1.rs index 2c530531e..993701d4b 100644 --- a/crates/iota-crypto/src/secp256r1.rs +++ b/crates/iota-crypto/src/secp256r1.rs @@ -150,25 +150,24 @@ impl crate::FromMnemonic for Secp256r1PrivateKey { fn from_mnemonic( phrase: &str, password: impl Into>, - path: impl Into>, + path: impl Into>, ) -> Result { use std::str::FromStr; use crate::FromBytes; - let mnemonic = bip32::Mnemonic::new(phrase, bip32::Language::English)?; + let mnemonic = bip39::Mnemonic::parse_in_normalized(bip39::Language::English, phrase)?; let seed = mnemonic.to_seed(&password.into().unwrap_or_default()); - let path = if let Some(path) = path.into() { - path - } else { - bip32::DerivationPath::from_str(&format!( + let path = path.into().unwrap_or_else(|| { + format!( "m/{}'/{}'/0'/0'/0'", crate::DERIVATION_PATH_PURPOSE_SECP256R1, crate::DERIVATION_PATH_COIN_TYPE - ))? - }; - let child_xprv = bip32::XPrv::derive_from_path(seed, &path)?; + ) + }); + let child_xprv = + bip32::XPrv::derive_from_path(seed, &bip32::DerivationPath::from_str(&path)?)?; Self::from_bytes(&child_xprv.private_key().to_bytes()) } } diff --git a/crates/iota-crypto/src/simple.rs b/crates/iota-crypto/src/simple.rs index d408cd6ca..54c26848b 100644 --- a/crates/iota-crypto/src/simple.rs +++ b/crates/iota-crypto/src/simple.rs @@ -333,7 +333,7 @@ mod keypair { scheme: SignatureScheme, phrase: &str, password: impl Into>, - path: impl Into>, + path: impl Into>, ) -> Result { use crate::FromMnemonic; diff --git a/crates/iota-sdk-ffi/src/crypto/ed25519.rs b/crates/iota-sdk-ffi/src/crypto/ed25519.rs index 1d9b22a00..eea600ae1 100644 --- a/crates/iota-sdk-ffi/src/crypto/ed25519.rs +++ b/crates/iota-sdk-ffi/src/crypto/ed25519.rs @@ -92,12 +92,7 @@ impl Ed25519PrivateKey { password: Option, path: Option, ) -> Result { - Ok(iota_crypto::ed25519::Ed25519PrivateKey::from_mnemonic( - phrase, - password, - path.map(|p| p.parse()).transpose()?, - )? - .into()) + Ok(iota_crypto::ed25519::Ed25519PrivateKey::from_mnemonic(phrase, password, path)?.into()) } pub fn try_sign(&self, message: &[u8]) -> Result { diff --git a/crates/iota-sdk-ffi/src/crypto/secp256k1.rs b/crates/iota-sdk-ffi/src/crypto/secp256k1.rs index 6be9aed59..d3373fdaa 100644 --- a/crates/iota-sdk-ffi/src/crypto/secp256k1.rs +++ b/crates/iota-sdk-ffi/src/crypto/secp256k1.rs @@ -92,12 +92,10 @@ impl Secp256k1PrivateKey { password: Option, path: Option, ) -> Result { - Ok(iota_crypto::secp256k1::Secp256k1PrivateKey::from_mnemonic( - phrase, - password, - path.map(|p| p.parse()).transpose()?, - )? - .into()) + Ok( + iota_crypto::secp256k1::Secp256k1PrivateKey::from_mnemonic(phrase, password, path)? + .into(), + ) } pub fn try_sign(&self, message: &[u8]) -> Result { diff --git a/crates/iota-sdk-ffi/src/crypto/secp256r1.rs b/crates/iota-sdk-ffi/src/crypto/secp256r1.rs index 18b005765..d1701acec 100644 --- a/crates/iota-sdk-ffi/src/crypto/secp256r1.rs +++ b/crates/iota-sdk-ffi/src/crypto/secp256r1.rs @@ -114,12 +114,10 @@ impl Secp256r1PrivateKey { password: Option, path: Option, ) -> Result { - Ok(iota_crypto::secp256r1::Secp256r1PrivateKey::from_mnemonic( - phrase, - password, - path.map(|p| p.parse()).transpose()?, - )? - .into()) + Ok( + iota_crypto::secp256r1::Secp256r1PrivateKey::from_mnemonic(phrase, password, path)? + .into(), + ) } } diff --git a/crates/iota-sdk-ffi/src/crypto/simple.rs b/crates/iota-sdk-ffi/src/crypto/simple.rs index e7d9f9c99..79f29b080 100644 --- a/crates/iota-sdk-ffi/src/crypto/simple.rs +++ b/crates/iota-sdk-ffi/src/crypto/simple.rs @@ -121,13 +121,10 @@ impl SimpleKeypair { password: Option, path: Option, ) -> Result { - Ok(iota_crypto::simple::SimpleKeypair::from_mnemonic( - scheme, - phrase, - password, - path.map(|p| p.parse()).transpose()?, - )? - .into()) + Ok( + iota_crypto::simple::SimpleKeypair::from_mnemonic(scheme, phrase, password, path)? + .into(), + ) } fn try_sign(&self, message: &[u8]) -> Result { diff --git a/crates/iota-sdk/examples/address_from_mnemonic.rs b/crates/iota-sdk/examples/address_from_mnemonic.rs new file mode 100644 index 000000000..b67b411cb --- /dev/null +++ b/crates/iota-sdk/examples/address_from_mnemonic.rs @@ -0,0 +1,51 @@ +// Copyright (c) 2025 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use base64ct::{Base64, Encoding}; +use iota_crypto::{ + FromMnemonic, ToFromBech32, ed25519::Ed25519PrivateKey, secp256k1::Secp256k1PrivateKey, + secp256r1::Secp256r1PrivateKey, +}; +use iota_types::PublicKeyExt; + +const MNEMONIC: &str = "round attack kitchen wink winter music trip tiny nephew hire orange what"; + +fn main() -> eyre::Result<()> { + let private_key = Ed25519PrivateKey::from_mnemonic(MNEMONIC, None, None)?; + let private_key_bech32 = private_key.to_bech32().unwrap(); + let public_key = private_key.public_key(); + let flagged_public_key = Base64::encode_string(&public_key.to_flagged_bytes()); + let address = public_key.derive_address(); + + println!("Ed25519\n---"); + println!("Private Key: {private_key_bech32}"); + println!("Public Key: {public_key}"); + println!("Public Key With Flag: {flagged_public_key}"); + println!("Address: {address}"); + + let private_key = Secp256k1PrivateKey::from_mnemonic(MNEMONIC, None, None)?; + let private_key_bech32 = private_key.to_bech32().unwrap(); + let public_key = private_key.public_key(); + let flagged_public_key = Base64::encode_string(&public_key.to_flagged_bytes()); + let address = public_key.derive_address(); + + println!("\nSecp256k1\n---"); + println!("Private Key: {private_key_bech32}"); + println!("Public Key: {public_key}"); + println!("Public Key With Flag: {flagged_public_key}"); + println!("Address: {address}"); + + let private_key = Secp256r1PrivateKey::from_mnemonic(MNEMONIC, None, None)?; + let private_key_bech32 = private_key.to_bech32().unwrap(); + let public_key = private_key.public_key(); + let flagged_public_key = Base64::encode_string(&public_key.to_flagged_bytes()); + let address = public_key.derive_address(); + + println!("\nSecp256r1\n---"); + println!("Private Key: {private_key_bech32}"); + println!("Public Key: {public_key}"); + println!("Public Key With Flag: {flagged_public_key}"); + println!("Address: {address}"); + + Ok(()) +} From e3cd399aa5fa272f360152f349767139f0ab79a8 Mon Sep 17 00:00:00 2001 From: Chloe Martin Date: Tue, 28 Oct 2025 11:08:25 +0100 Subject: [PATCH 05/12] bindings examples --- .../go/examples/address_from_mnemonic/main.go | 70 +++++++++++++++++++ .../kotlin/examples/AddressFromMnemonic.kt | 48 +++++++++++++ .../python/examples/address_from_mnemonic.py | 48 +++++++++++++ 3 files changed, 166 insertions(+) create mode 100644 bindings/go/examples/address_from_mnemonic/main.go create mode 100644 bindings/kotlin/examples/AddressFromMnemonic.kt create mode 100644 bindings/python/examples/address_from_mnemonic.py diff --git a/bindings/go/examples/address_from_mnemonic/main.go b/bindings/go/examples/address_from_mnemonic/main.go new file mode 100644 index 000000000..306594a4c --- /dev/null +++ b/bindings/go/examples/address_from_mnemonic/main.go @@ -0,0 +1,70 @@ +// Copyright (c) 2025 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +package main + +import ( + "fmt" + "log" + + sdk "bindings/iota_sdk_ffi" +) + +const MNEMONIC = "round attack kitchen wink winter music trip tiny nephew hire orange what" + +func main() { + privateKeyEd25519, err := sdk.Ed25519PrivateKeyFromMnemonic(MNEMONIC, nil, nil) + if err != nil { + log.Fatalf("Failed to get key from mnemonic: %v", err) + } + privateKeyEd25519Bech32, err := privateKeyEd25519.ToBech32() + if err != nil { + log.Fatalf("Failed to convert to bech32: %v", err) + } + publicKeyEd25519 := privateKeyEd25519.PublicKey() + flaggedPublicKeyEd25519 := publicKeyEd25519.ToFlaggedBytes() + addressEd25519 := publicKeyEd25519.DeriveAddress() + + fmt.Println("Ed25519\n---:") + fmt.Println("Private Key:", privateKeyEd25519Bech32) + fmt.Println("Public Key:", sdk.Base64Encode(publicKeyEd25519.ToBytes())) + fmt.Println("Public Key With Flag:", sdk.Base64Encode(flaggedPublicKeyEd25519)) + fmt.Println("Address:", addressEd25519.ToHex()) + + privateKeySecp256k1, err := sdk.Secp256k1PrivateKeyFromMnemonic(MNEMONIC, nil, nil) + if err != nil { + log.Fatalf("Failed to get key from mnemonic: %v", err) + } + privateKeySecp256k1Bech32, err := privateKeySecp256k1.ToBech32() + if err != nil { + log.Fatalf("Failed to convert to bech32: %v", err) + } + publicKeySecp256k1 := privateKeySecp256k1.PublicKey() + flaggedPublicKeySecp256k1 := publicKeySecp256k1.ToFlaggedBytes() + addressSecp256k1 := publicKeySecp256k1.DeriveAddress() + + fmt.Println("\nSecp256k1\n---:") + fmt.Println("Private Key:", privateKeySecp256k1Bech32) + fmt.Println("Public Key:", sdk.Base64Encode(publicKeySecp256k1.ToBytes())) + fmt.Println("Public Key With Flag:", sdk.Base64Encode(flaggedPublicKeySecp256k1)) + fmt.Println("Address:", addressSecp256k1.ToHex()) + + privateKeySecp256r1, err := sdk.Secp256r1PrivateKeyFromMnemonic(MNEMONIC, nil, nil) + if err != nil { + log.Fatalf("Failed to get key from mnemonic: %v", err) + } + privateKeySecp256r1Bech32, err := privateKeySecp256r1.ToBech32() + if err != nil { + log.Fatalf("Failed to convert to bech32: %v", err) + } + publicKeySecp256r1 := privateKeySecp256r1.PublicKey() + flaggedPublicKeySecp256r1 := publicKeySecp256r1.ToFlaggedBytes() + addressSecp256r1 := publicKeySecp256r1.DeriveAddress() + + fmt.Println("\nSecp256r1\n---:") + fmt.Println("Private Key:", privateKeySecp256r1Bech32) + fmt.Println("Public Key:", sdk.Base64Encode(publicKeySecp256r1.ToBytes())) + fmt.Println("Public Key With Flag:", sdk.Base64Encode(flaggedPublicKeySecp256r1)) + fmt.Println("Address:", addressSecp256r1.ToHex()) + +} diff --git a/bindings/kotlin/examples/AddressFromMnemonic.kt b/bindings/kotlin/examples/AddressFromMnemonic.kt new file mode 100644 index 000000000..333e3b536 --- /dev/null +++ b/bindings/kotlin/examples/AddressFromMnemonic.kt @@ -0,0 +1,48 @@ +// Copyright (c) 2025 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +import iota_sdk.Ed25519PrivateKey +import iota_sdk.Secp256k1PrivateKey +import iota_sdk.Secp256r1PrivateKey +import iota_sdk.base64Encode +import kotlin.io.println + +const val MNEMONIC = "round attack kitchen wink winter music trip tiny nephew hire orange what" + +fun main() { + val privateKeyEd25519 = Ed25519PrivateKey.fromMnemonic(MNEMONIC) + val privateKeyEd25519Bech32 = privateKeyEd25519.toBech32() + val publicKeyEd25519 = privateKeyEd25519.publicKey() + val flaggedPublicKeyEd25519 = publicKeyEd25519.toFlaggedBytes() + val addressEd25519 = publicKeyEd25519.deriveAddress() + + println("Ed25519\n---") + println("Private Key: ${privateKeyEd25519Bech32}") + println("Public Key: ${base64Encode(publicKeyEd25519.toBytes())}") + println("Public Key With Flag: ${base64Encode(flaggedPublicKeyEd25519)}") + println("Address: ${addressEd25519.toHex()}") + + val privateKeySecp256k1 = Secp256k1PrivateKey.fromMnemonic(MNEMONIC) + val privateKeySecp256k1Bech32 = privateKeySecp256k1.toBech32() + val publicKeySecp256k1 = privateKeySecp256k1.publicKey() + val flaggedPublicKeySecp256k1 = publicKeySecp256k1.toFlaggedBytes() + val addressSecp256k1 = publicKeySecp256k1.deriveAddress() + + println("\nSecp256k1\n---") + println("Private Key: ${privateKeySecp256k1Bech32}") + println("Public Key: ${base64Encode(publicKeySecp256k1.toBytes())}") + println("Public Key With Flag: ${base64Encode(flaggedPublicKeySecp256k1)}") + println("Address: ${addressSecp256k1.toHex()}") + + val privateKeySecp256r1 = Secp256r1PrivateKey.fromMnemonic(MNEMONIC) + val privateKeySecp256r1Bech32 = privateKeySecp256r1.toBech32() + val publicKeySecp256r1 = privateKeySecp256r1.publicKey() + val flaggedPublicKeySecp256r1 = publicKeySecp256r1.toFlaggedBytes() + val addressSecp256r1 = publicKeySecp256r1.deriveAddress() + + println("\nSecp256r1\n---") + println("Private Key: ${privateKeySecp256r1Bech32}") + println("Public Key: ${base64Encode(publicKeySecp256r1.toBytes())}") + println("Public Key With Flag: ${base64Encode(flaggedPublicKeySecp256r1)}") + println("Address: ${addressSecp256r1.toHex()}") +} diff --git a/bindings/python/examples/address_from_mnemonic.py b/bindings/python/examples/address_from_mnemonic.py new file mode 100644 index 000000000..adadc4020 --- /dev/null +++ b/bindings/python/examples/address_from_mnemonic.py @@ -0,0 +1,48 @@ +# Copyright (c) 2025 IOTA Stiftung +# SPDX-License-Identifier: Apache-2.0 + +from lib.iota_sdk_ffi import * + +MNEMONIC = "round attack kitchen wink winter music trip tiny nephew hire orange what" + + +def main(): + private_key = Ed25519PrivateKey.from_mnemonic(MNEMONIC) + private_key_bech32 = private_key.to_bech32() + public_key = private_key.public_key() + flagged_public_key = public_key.to_flagged_bytes() + address = public_key.derive_address() + + print(f"Ed25519\n---") + print(f"Private Key: {private_key_bech32}") + print(f"Public Key: {base64_encode(public_key.to_bytes())}") + print(f"Public Key With Flag: {base64_encode(flagged_public_key)}") + print(f"Address: {address.to_hex()}") + + private_key = Secp256k1PrivateKey.from_mnemonic(MNEMONIC) + private_key_bech32 = private_key.to_bech32() + public_key = private_key.public_key() + flagged_public_key = public_key.to_flagged_bytes() + address = public_key.derive_address() + + print(f"\nSecp256k1\n---") + print(f"Private Key: {private_key_bech32}") + print(f"Public Key: {base64_encode(public_key.to_bytes())}") + print(f"Public Key With Flag: {base64_encode(flagged_public_key)}") + print(f"Address: {address.to_hex()}") + + private_key = Secp256r1PrivateKey.from_mnemonic(MNEMONIC) + private_key_bech32 = private_key.to_bech32() + public_key = private_key.public_key() + flagged_public_key = public_key.to_flagged_bytes() + address = public_key.derive_address() + + print(f"\nSecp256r1\n---") + print(f"Private Key: {private_key_bech32}") + print(f"Public Key: {base64_encode(public_key.to_bytes())}") + print(f"Public Key With Flag: {base64_encode(flagged_public_key)}") + print(f"Address: {address.to_hex()}") + + +if __name__ == "__main__": + main() From 470f454b801064644e075fa024658e72fcdbb471 Mon Sep 17 00:00:00 2001 From: Chloe Martin Date: Tue, 28 Oct 2025 11:31:00 +0100 Subject: [PATCH 06/12] clippy --- crates/iota-crypto/src/ed25519.rs | 2 +- crates/iota-crypto/src/secp256k1.rs | 2 +- crates/iota-crypto/src/secp256r1.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/iota-crypto/src/ed25519.rs b/crates/iota-crypto/src/ed25519.rs index c3fc36962..3bab2b513 100644 --- a/crates/iota-crypto/src/ed25519.rs +++ b/crates/iota-crypto/src/ed25519.rs @@ -150,7 +150,7 @@ impl crate::FromMnemonic for Ed25519PrivateKey { use std::str::FromStr; let mnemonic = bip39::Mnemonic::parse_in_normalized(bip39::Language::English, phrase)?; - let seed = mnemonic.to_seed(&password.into().unwrap_or_default()); + let seed = mnemonic.to_seed(password.into().unwrap_or_default()); let path = path.into().unwrap_or_else(|| { format!( "m/{}'/{}'/0'/0'/0'", diff --git a/crates/iota-crypto/src/secp256k1.rs b/crates/iota-crypto/src/secp256k1.rs index 3342511fc..7b48adf20 100644 --- a/crates/iota-crypto/src/secp256k1.rs +++ b/crates/iota-crypto/src/secp256k1.rs @@ -157,7 +157,7 @@ impl crate::FromMnemonic for Secp256k1PrivateKey { use crate::FromBytes; let mnemonic = bip39::Mnemonic::parse_in_normalized(bip39::Language::English, phrase)?; - let seed = mnemonic.to_seed(&password.into().unwrap_or_default()); + let seed = mnemonic.to_seed(password.into().unwrap_or_default()); let path = path.into().unwrap_or_else(|| { format!( "m/{}'/{}'/0'/0'/0'", diff --git a/crates/iota-crypto/src/secp256r1.rs b/crates/iota-crypto/src/secp256r1.rs index 993701d4b..b3d877138 100644 --- a/crates/iota-crypto/src/secp256r1.rs +++ b/crates/iota-crypto/src/secp256r1.rs @@ -157,7 +157,7 @@ impl crate::FromMnemonic for Secp256r1PrivateKey { use crate::FromBytes; let mnemonic = bip39::Mnemonic::parse_in_normalized(bip39::Language::English, phrase)?; - let seed = mnemonic.to_seed(&password.into().unwrap_or_default()); + let seed = mnemonic.to_seed(password.into().unwrap_or_default()); let path = path.into().unwrap_or_else(|| { format!( From 604dc6e8014bb01a3d1a20a2b9174f5e24c90f92 Mon Sep 17 00:00:00 2001 From: Chloe Martin Date: Wed, 29 Oct 2025 10:36:52 +0100 Subject: [PATCH 07/12] add password and path to example --- crates/iota-sdk/examples/address_from_mnemonic.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/crates/iota-sdk/examples/address_from_mnemonic.rs b/crates/iota-sdk/examples/address_from_mnemonic.rs index b67b411cb..f95ff282f 100644 --- a/crates/iota-sdk/examples/address_from_mnemonic.rs +++ b/crates/iota-sdk/examples/address_from_mnemonic.rs @@ -3,8 +3,8 @@ use base64ct::{Base64, Encoding}; use iota_crypto::{ - FromMnemonic, ToFromBech32, ed25519::Ed25519PrivateKey, secp256k1::Secp256k1PrivateKey, - secp256r1::Secp256r1PrivateKey, + DERIVATION_PATH_COIN_TYPE, DERIVATION_PATH_PURPOSE_SECP256R1, FromMnemonic, ToFromBech32, + ed25519::Ed25519PrivateKey, secp256k1::Secp256k1PrivateKey, secp256r1::Secp256r1PrivateKey, }; use iota_types::PublicKeyExt; @@ -23,7 +23,7 @@ fn main() -> eyre::Result<()> { println!("Public Key With Flag: {flagged_public_key}"); println!("Address: {address}"); - let private_key = Secp256k1PrivateKey::from_mnemonic(MNEMONIC, None, None)?; + let private_key = Secp256k1PrivateKey::from_mnemonic(MNEMONIC, "my_password".to_owned(), None)?; let private_key_bech32 = private_key.to_bech32().unwrap(); let public_key = private_key.public_key(); let flagged_public_key = Base64::encode_string(&public_key.to_flagged_bytes()); @@ -35,7 +35,11 @@ fn main() -> eyre::Result<()> { println!("Public Key With Flag: {flagged_public_key}"); println!("Address: {address}"); - let private_key = Secp256r1PrivateKey::from_mnemonic(MNEMONIC, None, None)?; + let private_key = Secp256r1PrivateKey::from_mnemonic( + MNEMONIC, + None, + format!("m/{DERIVATION_PATH_PURPOSE_SECP256R1}'/{DERIVATION_PATH_COIN_TYPE}'/0'/0'/1'"), + )?; let private_key_bech32 = private_key.to_bech32().unwrap(); let public_key = private_key.public_key(); let flagged_public_key = Base64::encode_string(&public_key.to_flagged_bytes()); From 120ffb4b5b1fcc7e97153f684c7ab2f60990a460 Mon Sep 17 00:00:00 2001 From: Chloe Martin Date: Thu, 30 Oct 2025 16:02:18 +0100 Subject: [PATCH 08/12] remove impls from `SimpleKeypair` --- crates/iota-sdk-crypto/src/ed25519.rs | 2 +- crates/iota-sdk-crypto/src/lib.rs | 15 +---- crates/iota-sdk-crypto/src/secp256k1.rs | 2 +- crates/iota-sdk-crypto/src/secp256r1.rs | 2 +- crates/iota-sdk-crypto/src/simple.rs | 82 ------------------------ crates/iota-sdk-ffi/src/crypto/simple.rs | 15 ----- 6 files changed, 6 insertions(+), 112 deletions(-) diff --git a/crates/iota-sdk-crypto/src/ed25519.rs b/crates/iota-sdk-crypto/src/ed25519.rs index 254a96f3a..b8b7b78e0 100644 --- a/crates/iota-sdk-crypto/src/ed25519.rs +++ b/crates/iota-sdk-crypto/src/ed25519.rs @@ -134,7 +134,7 @@ impl crate::FromBytes for Ed25519PrivateKey { } } -impl crate::ConstPrivateKeyScheme for Ed25519PrivateKey { +impl crate::PrivateKeyScheme for Ed25519PrivateKey { const SCHEME: SignatureScheme = SignatureScheme::Ed25519; } diff --git a/crates/iota-sdk-crypto/src/lib.rs b/crates/iota-sdk-crypto/src/lib.rs index 5a88b6264..8475edd5c 100644 --- a/crates/iota-sdk-crypto/src/lib.rs +++ b/crates/iota-sdk-crypto/src/lib.rs @@ -213,18 +213,11 @@ pub trait FromBytes { Self: Sized; } -/// Defines the const scheme of a private key -pub trait ConstPrivateKeyScheme { - const SCHEME: iota_types::SignatureScheme; -} - /// Defines the scheme of a private key pub trait PrivateKeyScheme { - /// Returns the signature scheme for this private key - fn scheme(&self) -> iota_types::SignatureScheme; -} + const SCHEME: iota_types::SignatureScheme; -impl PrivateKeyScheme for T { + /// Returns the signature scheme for this private key fn scheme(&self) -> iota_types::SignatureScheme { Self::SCHEME } @@ -244,9 +237,7 @@ pub trait ToFromFlaggedBytes { Self: Sized; } -impl + ConstPrivateKeyScheme> ToFromFlaggedBytes - for T -{ +impl + PrivateKeyScheme> ToFromFlaggedBytes for T { type Error = PrivateKeyError; /// Returns the bytes with signature scheme flag prepended diff --git a/crates/iota-sdk-crypto/src/secp256k1.rs b/crates/iota-sdk-crypto/src/secp256k1.rs index 05584144e..8f20b8b00 100644 --- a/crates/iota-sdk-crypto/src/secp256k1.rs +++ b/crates/iota-sdk-crypto/src/secp256k1.rs @@ -139,7 +139,7 @@ impl crate::FromBytes for Secp256k1PrivateKey { } } -impl crate::ConstPrivateKeyScheme for Secp256k1PrivateKey { +impl crate::PrivateKeyScheme for Secp256k1PrivateKey { const SCHEME: SignatureScheme = SignatureScheme::Secp256k1; } diff --git a/crates/iota-sdk-crypto/src/secp256r1.rs b/crates/iota-sdk-crypto/src/secp256r1.rs index fc56b2827..b59c50e32 100644 --- a/crates/iota-sdk-crypto/src/secp256r1.rs +++ b/crates/iota-sdk-crypto/src/secp256r1.rs @@ -139,7 +139,7 @@ impl crate::FromBytes for Secp256r1PrivateKey { } } -impl crate::ConstPrivateKeyScheme for Secp256r1PrivateKey { +impl crate::PrivateKeyScheme for Secp256r1PrivateKey { const SCHEME: SignatureScheme = SignatureScheme::Secp256r1; } diff --git a/crates/iota-sdk-crypto/src/simple.rs b/crates/iota-sdk-crypto/src/simple.rs index ab4a17968..962795b29 100644 --- a/crates/iota-sdk-crypto/src/simple.rs +++ b/crates/iota-sdk-crypto/src/simple.rs @@ -298,67 +298,6 @@ mod keypair { InnerKeypair::Secp256r1(private_key) => private_key.to_pem(), } } - - /// Decode a private key from Bech32 format with "iotaprivkey" prefix - #[cfg(feature = "bech32")] - pub fn from_bech32(value: &str) -> Result - where - Self: Sized, - { - use bech32::Hrp; - - let expected_hrp = Hrp::parse(crate::IOTA_PRIV_KEY_PREFIX) - .map_err(|e| crate::PrivateKeyError::Bech32Hrp(format!("{e}")))?; - - let (hrp, data) = bech32::decode(value) - .map_err(|e| crate::PrivateKeyError::Bech32(format!("decoding failed: {e}")))?; - - if hrp != expected_hrp { - return Err(crate::PrivateKeyError::Bech32Hrp(format!( - "expected {}, got {hrp}", - crate::IOTA_PRIV_KEY_PREFIX - ))); - } - - if data.is_empty() { - return Err(crate::PrivateKeyError::EmptyData("bech32 data".to_string())); - } - - Self::from_bytes(&data) - .map_err(|e| crate::PrivateKeyError::InvalidScheme(e.to_string())) - } - - #[cfg(feature = "mnemonic")] - pub fn from_mnemonic( - scheme: SignatureScheme, - phrase: &str, - password: impl Into>, - path: impl Into>, - ) -> Result { - use crate::FromMnemonic; - - Ok(match scheme { - #[cfg(feature = "ed25519")] - SignatureScheme::Ed25519 => { - crate::ed25519::Ed25519PrivateKey::from_mnemonic(phrase, password, path)?.into() - } - #[cfg(feature = "secp256k1")] - SignatureScheme::Secp256k1 => { - crate::secp256k1::Secp256k1PrivateKey::from_mnemonic(phrase, password, path)? - .into() - } - #[cfg(feature = "secp256r1")] - SignatureScheme::Secp256r1 => { - crate::secp256r1::Secp256r1PrivateKey::from_mnemonic(phrase, password, path)? - .into() - } - _ => { - return Err(crate::PrivateKeyError::InvalidScheme(format!( - "scheme not supported for derivation from mnemonic: {scheme}" - ))); - } - }) - } } impl Signer for SimpleKeypair { @@ -601,27 +540,6 @@ mod keypair { } } - impl crate::ToBytes for SimpleKeypair { - fn to_bytes(&self) -> Vec { - // For SimpleKeypair, to_bytes() already returns flagged bytes - // We need the raw key bytes without the flag for the trait - match &self.inner { - #[cfg(feature = "ed25519")] - InnerKeypair::Ed25519(private_key) => private_key.to_bytes().to_vec(), - #[cfg(feature = "secp256k1")] - InnerKeypair::Secp256k1(private_key) => private_key.to_bytes().as_slice().to_vec(), - #[cfg(feature = "secp256r1")] - InnerKeypair::Secp256r1(private_key) => private_key.to_bytes().as_slice().to_vec(), - } - } - } - - impl crate::PrivateKeyScheme for SimpleKeypair { - fn scheme(&self) -> iota_types::SignatureScheme { - self.scheme() - } - } - impl crate::ToFromFlaggedBytes for SimpleKeypair { type Error = crate::PrivateKeyError; diff --git a/crates/iota-sdk-ffi/src/crypto/simple.rs b/crates/iota-sdk-ffi/src/crypto/simple.rs index 67ad0680d..94af9fb4a 100644 --- a/crates/iota-sdk-ffi/src/crypto/simple.rs +++ b/crates/iota-sdk-ffi/src/crypto/simple.rs @@ -114,21 +114,6 @@ impl SimpleKeypair { Ok(self.0.to_pem()?) } - /// Construct the private key from a mnemonic phrase and the signature - /// scheme - #[uniffi::constructor(default(password = None, path = None))] - pub fn from_mnemonic( - scheme: SignatureScheme, - phrase: &str, - password: Option, - path: Option, - ) -> Result { - Ok( - iota_sdk::crypto::simple::SimpleKeypair::from_mnemonic(scheme, phrase, password, path)? - .into(), - ) - } - fn try_sign(&self, message: &[u8]) -> Result { Ok(Signer::::try_sign(&self.0, message)?.into()) } From cdeff58fc02152e6ef9b9ad4951aa6cd92213b62 Mon Sep 17 00:00:00 2001 From: Chloe Martin Date: Thu, 30 Oct 2025 16:15:35 +0100 Subject: [PATCH 09/12] add tests and fix secp256 generation --- crates/iota-sdk-crypto/src/ed25519.rs | 8 +- crates/iota-sdk-crypto/src/lib.rs | 121 +++++++++++++++++--- crates/iota-sdk-crypto/src/secp256k1.rs | 12 +- crates/iota-sdk-crypto/src/secp256r1.rs | 12 +- crates/iota-sdk-crypto/src/simple.rs | 2 +- crates/iota-sdk-ffi/src/crypto/ed25519.rs | 2 +- crates/iota-sdk-ffi/src/crypto/secp256k1.rs | 2 +- crates/iota-sdk-ffi/src/crypto/secp256r1.rs | 2 +- crates/iota-sdk-ffi/src/crypto/simple.rs | 2 +- 9 files changed, 123 insertions(+), 40 deletions(-) diff --git a/crates/iota-sdk-crypto/src/ed25519.rs b/crates/iota-sdk-crypto/src/ed25519.rs index b8b7b78e0..d7c81a5f1 100644 --- a/crates/iota-sdk-crypto/src/ed25519.rs +++ b/crates/iota-sdk-crypto/src/ed25519.rs @@ -111,15 +111,13 @@ impl Ed25519PrivateKey { } } -impl crate::ToBytes for Ed25519PrivateKey { +impl crate::ToFromBytes for Ed25519PrivateKey { + type Error = crate::PrivateKeyError; + /// Return the raw 32-byte private key fn to_bytes(&self) -> Vec { self.0.to_bytes().to_vec() } -} - -impl crate::FromBytes for Ed25519PrivateKey { - type Error = crate::PrivateKeyError; fn from_bytes(bytes: &[u8]) -> Result { if bytes.len() != Self::LENGTH { diff --git a/crates/iota-sdk-crypto/src/lib.rs b/crates/iota-sdk-crypto/src/lib.rs index 8475edd5c..b5ba12587 100644 --- a/crates/iota-sdk-crypto/src/lib.rs +++ b/crates/iota-sdk-crypto/src/lib.rs @@ -197,32 +197,29 @@ pub const DERIVATION_PATH_PURPOSE_SECP256K1: u32 = 54; #[cfg(feature = "mnemonic")] pub const DERIVATION_PATH_PURPOSE_SECP256R1: u32 = 74; -/// Defines a type which can be converted to bytes -pub trait ToBytes { - /// Returns the raw bytes of this type. - fn to_bytes(&self) -> Vec; +/// Defines the scheme of a private key +pub trait PrivateKeyScheme { + const SCHEME: iota_types::SignatureScheme; + + /// Returns the signature scheme for this private key + fn scheme(&self) -> iota_types::SignatureScheme { + Self::SCHEME + } } /// Defines a type which can be constructed from bytes -pub trait FromBytes { +pub trait ToFromBytes { type Error; + /// Returns the raw bytes of this type. + fn to_bytes(&self) -> Vec; + /// Create an instance from raw bytes fn from_bytes(bytes: &[u8]) -> Result where Self: Sized; } -/// Defines the scheme of a private key -pub trait PrivateKeyScheme { - const SCHEME: iota_types::SignatureScheme; - - /// Returns the signature scheme for this private key - fn scheme(&self) -> iota_types::SignatureScheme { - Self::SCHEME - } -} - /// Defines a type that can be converted to and from flagged bytes, i.e. bytes /// prepended by some variant indicator flag pub trait ToFromFlaggedBytes { @@ -237,7 +234,7 @@ pub trait ToFromFlaggedBytes { Self: Sized; } -impl + PrivateKeyScheme> ToFromFlaggedBytes for T { +impl + PrivateKeyScheme> ToFromFlaggedBytes for T { type Error = PrivateKeyError; /// Returns the bytes with signature scheme flag prepended @@ -341,3 +338,95 @@ pub trait FromMnemonic { where Self: Sized; } + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + ed25519::Ed25519PrivateKey, secp256k1::Secp256k1PrivateKey, secp256r1::Secp256r1PrivateKey, + }; + + #[cfg(feature = "mnemonic")] + #[test] + fn test_mnemonics_ed25519() { + const TEST_CASES: [[&str; 3]; 3] = [ + [ + "film crazy soon outside stand loop subway crumble thrive popular green nuclear struggle pistol arm wife phrase warfare march wheat nephew ask sunny firm", + "iotaprivkey1qrqqxhsu3ndp96644fjk4z5ams5ulgmvprklngt2jhvg2ujn5w4q2d2vplv", + "0x9f8e5379678525edf768d7b507dc1ba9016fc4f0eac976ab7f74077d95fba312", + ], + [ + "require decline left thought grid priority false tiny gasp angle royal system attack beef setup reward aunt skill wasp tray vital bounce inflict level", + "iotaprivkey1qqcxaf57fnenvflpacacaumf6vl0rt0edddhytanvzhkqhwnjk0zspg902d", + "0x862738192e40540e0a5c9a5aca636f53b0cd76b0a9bef3386e05647feb4914ac", + ], + [ + "organ crash swim stick traffic remember army arctic mesh slice swear summer police vast chaos cradle squirrel hood useless evidence pet hub soap lake", + "iotaprivkey1qzq39vxzm0gq7l8dc5dj5allpuww4mavhwhg8mua4cl3lj2c3fvhcv5l2vn", + "0x2391788ca49c7f0f00699bc2bad45f80c343b4d1df024285c132259433d7ff31", + ], + ]; + + for [mnemonic, bech32, address] in TEST_CASES { + let key = Ed25519PrivateKey::from_mnemonic(mnemonic, None, None).unwrap(); + assert_eq!(key.to_bech32().unwrap(), bech32); + assert_eq!(key.public_key().derive_address().to_string(), address); + } + } + + #[cfg(feature = "mnemonic")] + #[test] + fn test_mnemonics_secp256k1() { + const TEST_CASES: [[&str; 3]; 3] = [ + [ + "film crazy soon outside stand loop subway crumble thrive popular green nuclear struggle pistol arm wife phrase warfare march wheat nephew ask sunny firm", + "iotaprivkey1q8cy2ll8a0dmzzzwn9zavrug0qf47cyuj6k2r4r6rnjtpjhrdh52vpegd4f", + "0x8520d58dde1ab268349b9a46e5124ae6fe7e4c61df4ca2bc9c97d3c4d07b0b55", + ], + [ + "require decline left thought grid priority false tiny gasp angle royal system attack beef setup reward aunt skill wasp tray vital bounce inflict level", + "iotaprivkey1q9hm330d05jcxfvmztv046p8kclyaj39hk6elqghgpq4sz4x23hk2wd6cfz", + "0x3740d570eefba29dfc0fdd5829848902064e31ecd059ca05c401907fa8646f61", + ], + [ + "organ crash swim stick traffic remember army arctic mesh slice swear summer police vast chaos cradle squirrel hood useless evidence pet hub soap lake", + "iotaprivkey1qx2dnch6363h7gdqqfkzmmlequzj4ul3x4fq6dzyajk7wc2c0jgcx32axh5", + "0x943b852c37fef403047e06ff5a2fa216557a4386212fb29554babdd3e1899da5", + ], + ]; + + for [mnemonic, bech32, address] in TEST_CASES { + let key = Secp256k1PrivateKey::from_mnemonic(mnemonic, None, None).unwrap(); + assert_eq!(key.to_bech32().unwrap(), bech32); + assert_eq!(key.public_key().derive_address().to_string(), address); + } + } + + #[cfg(feature = "mnemonic")] + #[test] + fn test_mnemonics_secp256r1() { + const TEST_CASES: [[&str; 3]; 3] = [ + [ + "act wing dilemma glory episode region allow mad tourist humble muffin oblige", + "iotaprivkey1qtt65ua2lhal76zg4cxd6umdqynv2rj2gzrntp5rwlnyj370jg3pwtqlwdn", + "0x779a63b28528210a5ec6c4af5a70382fa3f0c2d3f98dcbe4e3a4ae2f8c39cc9c", + ], + [ + "flag rebel cabbage captain minimum purpose long already valley horn enrich salt", + "iotaprivkey1qtcjgmue7q8u4gtutfvfpx3zj3aa2r9pqssuusrltxfv68eqhzsgjc3p4z7", + "0x8b45523042933aa55f57e2ccc661304baed292529b6e67a0c9857c1f3f871806", + ], + [ + "area renew bar language pudding trial small host remind supreme cabbage era", + "iotaprivkey1qtxafg26qxeqy7f56gd2rvsup0a5kl4cre7nt2rtcrf0p3v5pwd4cgrrff2", + "0x8528ef86150ec331928a8b3edb8adbe2fb523db8c84679aa57a931da6a4cdb25", + ], + ]; + + for [mnemonic, bech32, address] in TEST_CASES { + let key = Secp256r1PrivateKey::from_mnemonic(mnemonic, None, None).unwrap(); + assert_eq!(key.to_bech32().unwrap(), bech32); + assert_eq!(key.public_key().derive_address().to_string(), address); + } + } +} diff --git a/crates/iota-sdk-crypto/src/secp256k1.rs b/crates/iota-sdk-crypto/src/secp256k1.rs index 8f20b8b00..13cbeb65c 100644 --- a/crates/iota-sdk-crypto/src/secp256k1.rs +++ b/crates/iota-sdk-crypto/src/secp256k1.rs @@ -116,15 +116,13 @@ impl Secp256k1PrivateKey { } } -impl crate::ToBytes for Secp256k1PrivateKey { +impl crate::ToFromBytes for Secp256k1PrivateKey { + type Error = crate::PrivateKeyError; + /// Return the raw 32-byte private key fn to_bytes(&self) -> Vec { self.0.to_bytes().to_vec() } -} - -impl crate::FromBytes for Secp256k1PrivateKey { - type Error = crate::PrivateKeyError; fn from_bytes(bytes: &[u8]) -> Result { if bytes.len() != Self::LENGTH { @@ -154,13 +152,13 @@ impl crate::FromMnemonic for Secp256k1PrivateKey { ) -> Result { use std::str::FromStr; - use crate::FromBytes; + use crate::ToFromBytes; let mnemonic = bip39::Mnemonic::parse_in_normalized(bip39::Language::English, phrase)?; let seed = mnemonic.to_seed(password.into().unwrap_or_default()); let path = path.into().unwrap_or_else(|| { format!( - "m/{}'/{}'/0'/0'/0'", + "m/{}'/{}'/0'/0/0", crate::DERIVATION_PATH_PURPOSE_SECP256K1, crate::DERIVATION_PATH_COIN_TYPE ) diff --git a/crates/iota-sdk-crypto/src/secp256r1.rs b/crates/iota-sdk-crypto/src/secp256r1.rs index b59c50e32..486f6e723 100644 --- a/crates/iota-sdk-crypto/src/secp256r1.rs +++ b/crates/iota-sdk-crypto/src/secp256r1.rs @@ -116,15 +116,13 @@ impl Secp256r1PrivateKey { } } -impl crate::ToBytes for Secp256r1PrivateKey { +impl crate::ToFromBytes for Secp256r1PrivateKey { + type Error = crate::PrivateKeyError; + /// Return the raw 32-byte private key fn to_bytes(&self) -> Vec { self.0.to_bytes().to_vec() } -} - -impl crate::FromBytes for Secp256r1PrivateKey { - type Error = crate::PrivateKeyError; fn from_bytes(bytes: &[u8]) -> Result { if bytes.len() != Self::LENGTH { @@ -154,14 +152,14 @@ impl crate::FromMnemonic for Secp256r1PrivateKey { ) -> Result { use std::str::FromStr; - use crate::FromBytes; + use crate::ToFromBytes; let mnemonic = bip39::Mnemonic::parse_in_normalized(bip39::Language::English, phrase)?; let seed = mnemonic.to_seed(password.into().unwrap_or_default()); let path = path.into().unwrap_or_else(|| { format!( - "m/{}'/{}'/0'/0'/0'", + "m/{}'/{}'/0'/0/0", crate::DERIVATION_PATH_PURPOSE_SECP256R1, crate::DERIVATION_PATH_COIN_TYPE ) diff --git a/crates/iota-sdk-crypto/src/simple.rs b/crates/iota-sdk-crypto/src/simple.rs index 962795b29..e862c42eb 100644 --- a/crates/iota-sdk-crypto/src/simple.rs +++ b/crates/iota-sdk-crypto/src/simple.rs @@ -138,7 +138,7 @@ mod keypair { /// Encode a SimpleKeypair as `flag || privkey` in bytes pub fn to_bytes(&self) -> Vec { - use crate::ToBytes; + use crate::ToFromBytes; let mut bytes = Vec::new(); bytes.push(self.scheme().to_u8()); diff --git a/crates/iota-sdk-ffi/src/crypto/ed25519.rs b/crates/iota-sdk-ffi/src/crypto/ed25519.rs index c1c98b8b3..40b3076f4 100644 --- a/crates/iota-sdk-ffi/src/crypto/ed25519.rs +++ b/crates/iota-sdk-ffi/src/crypto/ed25519.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use iota_sdk::{ - crypto::{FromMnemonic, ToBytes, ToFromBech32}, + crypto::{FromMnemonic, ToFromBech32, ToFromBytes}, types::SignatureScheme, }; use rand::rngs::OsRng; diff --git a/crates/iota-sdk-ffi/src/crypto/secp256k1.rs b/crates/iota-sdk-ffi/src/crypto/secp256k1.rs index 8b70cbd0f..557106649 100644 --- a/crates/iota-sdk-ffi/src/crypto/secp256k1.rs +++ b/crates/iota-sdk-ffi/src/crypto/secp256k1.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use iota_sdk::{ - crypto::{FromMnemonic, ToBytes, ToFromBech32}, + crypto::{FromMnemonic, ToFromBech32, ToFromBytes}, types::SignatureScheme, }; use rand::rngs::OsRng; diff --git a/crates/iota-sdk-ffi/src/crypto/secp256r1.rs b/crates/iota-sdk-ffi/src/crypto/secp256r1.rs index 3aa1f49fa..254f13975 100644 --- a/crates/iota-sdk-ffi/src/crypto/secp256r1.rs +++ b/crates/iota-sdk-ffi/src/crypto/secp256r1.rs @@ -4,7 +4,7 @@ use std::sync::Arc; use iota_sdk::{ - crypto::{FromMnemonic, Signer, ToBytes, ToFromBech32, Verifier}, + crypto::{FromMnemonic, Signer, ToFromBech32, ToFromBytes, Verifier}, types::SignatureScheme, }; use rand::rngs::OsRng; diff --git a/crates/iota-sdk-ffi/src/crypto/simple.rs b/crates/iota-sdk-ffi/src/crypto/simple.rs index 94af9fb4a..5179488cc 100644 --- a/crates/iota-sdk-ffi/src/crypto/simple.rs +++ b/crates/iota-sdk-ffi/src/crypto/simple.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use iota_sdk::{ - crypto::{Signer, ToBytes, ToFromBech32, Verifier}, + crypto::{Signer, ToFromBech32, Verifier}, types::SignatureScheme, }; From 9938467ac1b9a02fca5cc01472ec06b0ff81a6c0 Mon Sep 17 00:00:00 2001 From: Chloe Martin Date: Thu, 30 Oct 2025 16:35:19 +0100 Subject: [PATCH 10/12] split mnemonic methods --- .../go/examples/address_from_mnemonic/main.go | 6 +- bindings/go/iota_sdk_ffi/iota_sdk_ffi.go | 110 ++++++--- bindings/go/iota_sdk_ffi/iota_sdk_ffi.h | 50 +++-- .../kotlin/examples/AddressFromMnemonic.kt | 5 +- bindings/kotlin/lib/iota_sdk/iota_sdk_ffi.kt | 116 +++++++--- .../python/examples/address_from_mnemonic.py | 4 +- bindings/python/lib/iota_sdk_ffi.py | 208 ++++++++++++------ crates/iota-sdk-crypto/src/ed25519.rs | 31 ++- crates/iota-sdk-crypto/src/lib.rs | 14 +- crates/iota-sdk-crypto/src/secp256k1.rs | 31 ++- crates/iota-sdk-crypto/src/secp256r1.rs | 32 ++- crates/iota-sdk-ffi/src/crypto/ed25519.rs | 26 ++- crates/iota-sdk-ffi/src/crypto/secp256k1.rs | 24 +- crates/iota-sdk-ffi/src/crypto/secp256r1.rs | 24 +- .../examples/address_from_mnemonic.rs | 6 +- 15 files changed, 473 insertions(+), 214 deletions(-) diff --git a/bindings/go/examples/address_from_mnemonic/main.go b/bindings/go/examples/address_from_mnemonic/main.go index 306594a4c..9fda779ea 100644 --- a/bindings/go/examples/address_from_mnemonic/main.go +++ b/bindings/go/examples/address_from_mnemonic/main.go @@ -13,7 +13,7 @@ import ( const MNEMONIC = "round attack kitchen wink winter music trip tiny nephew hire orange what" func main() { - privateKeyEd25519, err := sdk.Ed25519PrivateKeyFromMnemonic(MNEMONIC, nil, nil) + privateKeyEd25519, err := sdk.Ed25519PrivateKeyFromMnemonic(MNEMONIC, 0, "") if err != nil { log.Fatalf("Failed to get key from mnemonic: %v", err) } @@ -31,7 +31,7 @@ func main() { fmt.Println("Public Key With Flag:", sdk.Base64Encode(flaggedPublicKeyEd25519)) fmt.Println("Address:", addressEd25519.ToHex()) - privateKeySecp256k1, err := sdk.Secp256k1PrivateKeyFromMnemonic(MNEMONIC, nil, nil) + privateKeySecp256k1, err := sdk.Secp256k1PrivateKeyFromMnemonic(MNEMONIC, 1, "my_password") if err != nil { log.Fatalf("Failed to get key from mnemonic: %v", err) } @@ -49,7 +49,7 @@ func main() { fmt.Println("Public Key With Flag:", sdk.Base64Encode(flaggedPublicKeySecp256k1)) fmt.Println("Address:", addressSecp256k1.ToHex()) - privateKeySecp256r1, err := sdk.Secp256r1PrivateKeyFromMnemonic(MNEMONIC, nil, nil) + privateKeySecp256r1, err := sdk.Secp256r1PrivateKeyFromMnemonicWithPath(MNEMONIC, "m/74'/4218'/0'/0/2", "") if err != nil { log.Fatalf("Failed to get key from mnemonic: %v", err) } diff --git a/bindings/go/iota_sdk_ffi/iota_sdk_ffi.go b/bindings/go/iota_sdk_ffi/iota_sdk_ffi.go index 56cd061af..d94784da1 100644 --- a/bindings/go/iota_sdk_ffi/iota_sdk_ffi.go +++ b/bindings/go/iota_sdk_ffi/iota_sdk_ffi.go @@ -7112,12 +7112,21 @@ func uniffiCheckChecksums() { checksum := rustCall(func(_uniffiStatus *C.RustCallStatus) C.uint16_t { return C.uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_mnemonic() }) - if checksum != 52060 { + if checksum != 55789 { // If this happens try cleaning and rebuilding your project panic("iota_sdk_ffi: uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_mnemonic: UniFFI API checksum mismatch") } } { + checksum := rustCall(func(_uniffiStatus *C.RustCallStatus) C.uint16_t { + return C.uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_mnemonic_with_path() + }) + if checksum != 15255 { + // If this happens try cleaning and rebuilding your project + panic("iota_sdk_ffi: uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_mnemonic_with_path: UniFFI API checksum mismatch") + } + } + { checksum := rustCall(func(_uniffiStatus *C.RustCallStatus) C.uint16_t { return C.uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_pem() }) @@ -8363,12 +8372,21 @@ func uniffiCheckChecksums() { checksum := rustCall(func(_uniffiStatus *C.RustCallStatus) C.uint16_t { return C.uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_mnemonic() }) - if checksum != 27698 { + if checksum != 33082 { // If this happens try cleaning and rebuilding your project panic("iota_sdk_ffi: uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_mnemonic: UniFFI API checksum mismatch") } } { + checksum := rustCall(func(_uniffiStatus *C.RustCallStatus) C.uint16_t { + return C.uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_mnemonic_with_path() + }) + if checksum != 7431 { + // If this happens try cleaning and rebuilding your project + panic("iota_sdk_ffi: uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_mnemonic_with_path: UniFFI API checksum mismatch") + } + } + { checksum := rustCall(func(_uniffiStatus *C.RustCallStatus) C.uint16_t { return C.uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_pem() }) @@ -8507,12 +8525,21 @@ func uniffiCheckChecksums() { checksum := rustCall(func(_uniffiStatus *C.RustCallStatus) C.uint16_t { return C.uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_mnemonic() }) - if checksum != 62413 { + if checksum != 57849 { // If this happens try cleaning and rebuilding your project panic("iota_sdk_ffi: uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_mnemonic: UniFFI API checksum mismatch") } } { + checksum := rustCall(func(_uniffiStatus *C.RustCallStatus) C.uint16_t { + return C.uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_mnemonic_with_path() + }) + if checksum != 7709 { + // If this happens try cleaning and rebuilding your project + panic("iota_sdk_ffi: uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_mnemonic_with_path: UniFFI API checksum mismatch") + } + } + { checksum := rustCall(func(_uniffiStatus *C.RustCallStatus) C.uint16_t { return C.uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_pem() }) @@ -8666,15 +8693,6 @@ func uniffiCheckChecksums() { } } { - checksum := rustCall(func(_uniffiStatus *C.RustCallStatus) C.uint16_t { - return C.uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_mnemonic() - }) - if checksum != 10406 { - // If this happens try cleaning and rebuilding your project - panic("iota_sdk_ffi: uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_mnemonic: UniFFI API checksum mismatch") - } - } - { checksum := rustCall(func(_uniffiStatus *C.RustCallStatus) C.uint16_t { return C.uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_pem() }) @@ -12722,9 +12740,23 @@ func Ed25519PrivateKeyFromDer(bytes []byte) (*Ed25519PrivateKey, error) { } // Construct the private key from a mnemonic phrase -func Ed25519PrivateKeyFromMnemonic(phrase string, password *string, path *string) (*Ed25519PrivateKey, error) { +func Ed25519PrivateKeyFromMnemonic(phrase string, accountIndex uint64, password string) (*Ed25519PrivateKey, error) { + _uniffiRV, _uniffiErr := rustCallWithError[SdkFfiError](FfiConverterSdkFfiError{},func(_uniffiStatus *C.RustCallStatus) unsafe.Pointer { + return C.uniffi_iota_sdk_ffi_fn_constructor_ed25519privatekey_from_mnemonic(FfiConverterStringINSTANCE.Lower(phrase), FfiConverterUint64INSTANCE.Lower(accountIndex), FfiConverterStringINSTANCE.Lower(password),_uniffiStatus) + }) + if _uniffiErr != nil { + var _uniffiDefaultValue *Ed25519PrivateKey + return _uniffiDefaultValue, _uniffiErr + } else { + return FfiConverterEd25519PrivateKeyINSTANCE.Lift(_uniffiRV), nil + } +} + +// Create an instance from a mnemonic phrase and a derivation path like +// `"m/44'/4218'/0'/0'/0'"` +func Ed25519PrivateKeyFromMnemonicWithPath(phrase string, path string, password string) (*Ed25519PrivateKey, error) { _uniffiRV, _uniffiErr := rustCallWithError[SdkFfiError](FfiConverterSdkFfiError{},func(_uniffiStatus *C.RustCallStatus) unsafe.Pointer { - return C.uniffi_iota_sdk_ffi_fn_constructor_ed25519privatekey_from_mnemonic(FfiConverterStringINSTANCE.Lower(phrase), FfiConverterOptionalStringINSTANCE.Lower(password), FfiConverterOptionalStringINSTANCE.Lower(path),_uniffiStatus) + return C.uniffi_iota_sdk_ffi_fn_constructor_ed25519privatekey_from_mnemonic_with_path(FfiConverterStringINSTANCE.Lower(phrase), FfiConverterStringINSTANCE.Lower(path), FfiConverterStringINSTANCE.Lower(password),_uniffiStatus) }) if _uniffiErr != nil { var _uniffiDefaultValue *Ed25519PrivateKey @@ -21253,9 +21285,23 @@ func Secp256k1PrivateKeyFromDer(bytes []byte) (*Secp256k1PrivateKey, error) { } // Construct the private key from a mnemonic phrase -func Secp256k1PrivateKeyFromMnemonic(phrase string, password *string, path *string) (*Secp256k1PrivateKey, error) { +func Secp256k1PrivateKeyFromMnemonic(phrase string, accountIndex uint64, password string) (*Secp256k1PrivateKey, error) { + _uniffiRV, _uniffiErr := rustCallWithError[SdkFfiError](FfiConverterSdkFfiError{},func(_uniffiStatus *C.RustCallStatus) unsafe.Pointer { + return C.uniffi_iota_sdk_ffi_fn_constructor_secp256k1privatekey_from_mnemonic(FfiConverterStringINSTANCE.Lower(phrase), FfiConverterUint64INSTANCE.Lower(accountIndex), FfiConverterStringINSTANCE.Lower(password),_uniffiStatus) + }) + if _uniffiErr != nil { + var _uniffiDefaultValue *Secp256k1PrivateKey + return _uniffiDefaultValue, _uniffiErr + } else { + return FfiConverterSecp256k1PrivateKeyINSTANCE.Lift(_uniffiRV), nil + } +} + +// Create an instance from a mnemonic phrase and a derivation path like +// `"m/54'/4218'/0'/0/0"` +func Secp256k1PrivateKeyFromMnemonicWithPath(phrase string, path string, password string) (*Secp256k1PrivateKey, error) { _uniffiRV, _uniffiErr := rustCallWithError[SdkFfiError](FfiConverterSdkFfiError{},func(_uniffiStatus *C.RustCallStatus) unsafe.Pointer { - return C.uniffi_iota_sdk_ffi_fn_constructor_secp256k1privatekey_from_mnemonic(FfiConverterStringINSTANCE.Lower(phrase), FfiConverterOptionalStringINSTANCE.Lower(password), FfiConverterOptionalStringINSTANCE.Lower(path),_uniffiStatus) + return C.uniffi_iota_sdk_ffi_fn_constructor_secp256k1privatekey_from_mnemonic_with_path(FfiConverterStringINSTANCE.Lower(phrase), FfiConverterStringINSTANCE.Lower(path), FfiConverterStringINSTANCE.Lower(password),_uniffiStatus) }) if _uniffiErr != nil { var _uniffiDefaultValue *Secp256k1PrivateKey @@ -22108,9 +22154,23 @@ func Secp256r1PrivateKeyFromDer(bytes []byte) (*Secp256r1PrivateKey, error) { } // Construct the private key from a mnemonic phrase -func Secp256r1PrivateKeyFromMnemonic(phrase string, password *string, path *string) (*Secp256r1PrivateKey, error) { +func Secp256r1PrivateKeyFromMnemonic(phrase string, accountIndex uint64, password string) (*Secp256r1PrivateKey, error) { + _uniffiRV, _uniffiErr := rustCallWithError[SdkFfiError](FfiConverterSdkFfiError{},func(_uniffiStatus *C.RustCallStatus) unsafe.Pointer { + return C.uniffi_iota_sdk_ffi_fn_constructor_secp256r1privatekey_from_mnemonic(FfiConverterStringINSTANCE.Lower(phrase), FfiConverterUint64INSTANCE.Lower(accountIndex), FfiConverterStringINSTANCE.Lower(password),_uniffiStatus) + }) + if _uniffiErr != nil { + var _uniffiDefaultValue *Secp256r1PrivateKey + return _uniffiDefaultValue, _uniffiErr + } else { + return FfiConverterSecp256r1PrivateKeyINSTANCE.Lift(_uniffiRV), nil + } +} + +// Create an instance from a mnemonic phrase and a derivation path like +// `"m/74'/4218'/0'/0/0"` +func Secp256r1PrivateKeyFromMnemonicWithPath(phrase string, path string, password string) (*Secp256r1PrivateKey, error) { _uniffiRV, _uniffiErr := rustCallWithError[SdkFfiError](FfiConverterSdkFfiError{},func(_uniffiStatus *C.RustCallStatus) unsafe.Pointer { - return C.uniffi_iota_sdk_ffi_fn_constructor_secp256r1privatekey_from_mnemonic(FfiConverterStringINSTANCE.Lower(phrase), FfiConverterOptionalStringINSTANCE.Lower(password), FfiConverterOptionalStringINSTANCE.Lower(path),_uniffiStatus) + return C.uniffi_iota_sdk_ffi_fn_constructor_secp256r1privatekey_from_mnemonic_with_path(FfiConverterStringINSTANCE.Lower(phrase), FfiConverterStringINSTANCE.Lower(path), FfiConverterStringINSTANCE.Lower(password),_uniffiStatus) }) if _uniffiErr != nil { var _uniffiDefaultValue *Secp256r1PrivateKey @@ -22970,20 +23030,6 @@ func SimpleKeypairFromEd25519(keypair *Ed25519PrivateKey) *SimpleKeypair { })) } -// Construct the private key from a mnemonic phrase and the signature -// scheme -func SimpleKeypairFromMnemonic(scheme SignatureScheme, phrase string, password *string, path *string) (*SimpleKeypair, error) { - _uniffiRV, _uniffiErr := rustCallWithError[SdkFfiError](FfiConverterSdkFfiError{},func(_uniffiStatus *C.RustCallStatus) unsafe.Pointer { - return C.uniffi_iota_sdk_ffi_fn_constructor_simplekeypair_from_mnemonic(FfiConverterSignatureSchemeINSTANCE.Lower(scheme), FfiConverterStringINSTANCE.Lower(phrase), FfiConverterOptionalStringINSTANCE.Lower(password), FfiConverterOptionalStringINSTANCE.Lower(path),_uniffiStatus) - }) - if _uniffiErr != nil { - var _uniffiDefaultValue *SimpleKeypair - return _uniffiDefaultValue, _uniffiErr - } else { - return FfiConverterSimpleKeypairINSTANCE.Lift(_uniffiRV), nil - } -} - // Deserialize PKCS#8-encoded private key from PEM. func SimpleKeypairFromPem(s string) (*SimpleKeypair, error) { _uniffiRV, _uniffiErr := rustCallWithError[SdkFfiError](FfiConverterSdkFfiError{},func(_uniffiStatus *C.RustCallStatus) unsafe.Pointer { diff --git a/bindings/go/iota_sdk_ffi/iota_sdk_ffi.h b/bindings/go/iota_sdk_ffi/iota_sdk_ffi.h index 8b005a64c..54fad6142 100644 --- a/bindings/go/iota_sdk_ffi/iota_sdk_ffi.h +++ b/bindings/go/iota_sdk_ffi/iota_sdk_ffi.h @@ -1170,7 +1170,12 @@ void* uniffi_iota_sdk_ffi_fn_constructor_ed25519privatekey_from_der(RustBuffer b #endif #ifndef UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_FN_CONSTRUCTOR_ED25519PRIVATEKEY_FROM_MNEMONIC #define UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_FN_CONSTRUCTOR_ED25519PRIVATEKEY_FROM_MNEMONIC -void* uniffi_iota_sdk_ffi_fn_constructor_ed25519privatekey_from_mnemonic(RustBuffer phrase, RustBuffer password, RustBuffer path, RustCallStatus *out_status +void* uniffi_iota_sdk_ffi_fn_constructor_ed25519privatekey_from_mnemonic(RustBuffer phrase, uint64_t account_index, RustBuffer password, RustCallStatus *out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_FN_CONSTRUCTOR_ED25519PRIVATEKEY_FROM_MNEMONIC_WITH_PATH +#define UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_FN_CONSTRUCTOR_ED25519PRIVATEKEY_FROM_MNEMONIC_WITH_PATH +void* uniffi_iota_sdk_ffi_fn_constructor_ed25519privatekey_from_mnemonic_with_path(RustBuffer phrase, RustBuffer path, RustBuffer password, RustCallStatus *out_status ); #endif #ifndef UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_FN_CONSTRUCTOR_ED25519PRIVATEKEY_FROM_PEM @@ -3390,7 +3395,12 @@ void* uniffi_iota_sdk_ffi_fn_constructor_secp256k1privatekey_from_der(RustBuffer #endif #ifndef UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_FN_CONSTRUCTOR_SECP256K1PRIVATEKEY_FROM_MNEMONIC #define UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_FN_CONSTRUCTOR_SECP256K1PRIVATEKEY_FROM_MNEMONIC -void* uniffi_iota_sdk_ffi_fn_constructor_secp256k1privatekey_from_mnemonic(RustBuffer phrase, RustBuffer password, RustBuffer path, RustCallStatus *out_status +void* uniffi_iota_sdk_ffi_fn_constructor_secp256k1privatekey_from_mnemonic(RustBuffer phrase, uint64_t account_index, RustBuffer password, RustCallStatus *out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_FN_CONSTRUCTOR_SECP256K1PRIVATEKEY_FROM_MNEMONIC_WITH_PATH +#define UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_FN_CONSTRUCTOR_SECP256K1PRIVATEKEY_FROM_MNEMONIC_WITH_PATH +void* uniffi_iota_sdk_ffi_fn_constructor_secp256k1privatekey_from_mnemonic_with_path(RustBuffer phrase, RustBuffer path, RustBuffer password, RustCallStatus *out_status ); #endif #ifndef UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_FN_CONSTRUCTOR_SECP256K1PRIVATEKEY_FROM_PEM @@ -3639,7 +3649,12 @@ void* uniffi_iota_sdk_ffi_fn_constructor_secp256r1privatekey_from_der(RustBuffer #endif #ifndef UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_FN_CONSTRUCTOR_SECP256R1PRIVATEKEY_FROM_MNEMONIC #define UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_FN_CONSTRUCTOR_SECP256R1PRIVATEKEY_FROM_MNEMONIC -void* uniffi_iota_sdk_ffi_fn_constructor_secp256r1privatekey_from_mnemonic(RustBuffer phrase, RustBuffer password, RustBuffer path, RustCallStatus *out_status +void* uniffi_iota_sdk_ffi_fn_constructor_secp256r1privatekey_from_mnemonic(RustBuffer phrase, uint64_t account_index, RustBuffer password, RustCallStatus *out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_FN_CONSTRUCTOR_SECP256R1PRIVATEKEY_FROM_MNEMONIC_WITH_PATH +#define UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_FN_CONSTRUCTOR_SECP256R1PRIVATEKEY_FROM_MNEMONIC_WITH_PATH +void* uniffi_iota_sdk_ffi_fn_constructor_secp256r1privatekey_from_mnemonic_with_path(RustBuffer phrase, RustBuffer path, RustBuffer password, RustCallStatus *out_status ); #endif #ifndef UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_FN_CONSTRUCTOR_SECP256R1PRIVATEKEY_FROM_PEM @@ -3896,11 +3911,6 @@ void* uniffi_iota_sdk_ffi_fn_constructor_simplekeypair_from_der(RustBuffer bytes void* uniffi_iota_sdk_ffi_fn_constructor_simplekeypair_from_ed25519(void* keypair, RustCallStatus *out_status ); #endif -#ifndef UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_FN_CONSTRUCTOR_SIMPLEKEYPAIR_FROM_MNEMONIC -#define UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_FN_CONSTRUCTOR_SIMPLEKEYPAIR_FROM_MNEMONIC -void* uniffi_iota_sdk_ffi_fn_constructor_simplekeypair_from_mnemonic(RustBuffer scheme, RustBuffer phrase, RustBuffer password, RustBuffer path, RustCallStatus *out_status -); -#endif #ifndef UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_FN_CONSTRUCTOR_SIMPLEKEYPAIR_FROM_PEM #define UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_FN_CONSTRUCTOR_SIMPLEKEYPAIR_FROM_PEM void* uniffi_iota_sdk_ffi_fn_constructor_simplekeypair_from_pem(RustBuffer s, RustCallStatus *out_status @@ -11258,6 +11268,12 @@ uint16_t uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_der(voi #define UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_CHECKSUM_CONSTRUCTOR_ED25519PRIVATEKEY_FROM_MNEMONIC uint16_t uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_mnemonic(void +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_CHECKSUM_CONSTRUCTOR_ED25519PRIVATEKEY_FROM_MNEMONIC_WITH_PATH +#define UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_CHECKSUM_CONSTRUCTOR_ED25519PRIVATEKEY_FROM_MNEMONIC_WITH_PATH +uint16_t uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_mnemonic_with_path(void + ); #endif #ifndef UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_CHECKSUM_CONSTRUCTOR_ED25519PRIVATEKEY_FROM_PEM @@ -12092,6 +12108,12 @@ uint16_t uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_der(v #define UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_CHECKSUM_CONSTRUCTOR_SECP256K1PRIVATEKEY_FROM_MNEMONIC uint16_t uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_mnemonic(void +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_CHECKSUM_CONSTRUCTOR_SECP256K1PRIVATEKEY_FROM_MNEMONIC_WITH_PATH +#define UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_CHECKSUM_CONSTRUCTOR_SECP256K1PRIVATEKEY_FROM_MNEMONIC_WITH_PATH +uint16_t uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_mnemonic_with_path(void + ); #endif #ifndef UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_CHECKSUM_CONSTRUCTOR_SECP256K1PRIVATEKEY_FROM_PEM @@ -12188,6 +12210,12 @@ uint16_t uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_der(v #define UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_CHECKSUM_CONSTRUCTOR_SECP256R1PRIVATEKEY_FROM_MNEMONIC uint16_t uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_mnemonic(void +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_CHECKSUM_CONSTRUCTOR_SECP256R1PRIVATEKEY_FROM_MNEMONIC_WITH_PATH +#define UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_CHECKSUM_CONSTRUCTOR_SECP256R1PRIVATEKEY_FROM_MNEMONIC_WITH_PATH +uint16_t uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_mnemonic_with_path(void + ); #endif #ifndef UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_CHECKSUM_CONSTRUCTOR_SECP256R1PRIVATEKEY_FROM_PEM @@ -12290,12 +12318,6 @@ uint16_t uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_der(void #define UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_CHECKSUM_CONSTRUCTOR_SIMPLEKEYPAIR_FROM_ED25519 uint16_t uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_ed25519(void -); -#endif -#ifndef UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_CHECKSUM_CONSTRUCTOR_SIMPLEKEYPAIR_FROM_MNEMONIC -#define UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_CHECKSUM_CONSTRUCTOR_SIMPLEKEYPAIR_FROM_MNEMONIC -uint16_t uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_mnemonic(void - ); #endif #ifndef UNIFFI_FFIDEF_UNIFFI_IOTA_SDK_FFI_CHECKSUM_CONSTRUCTOR_SIMPLEKEYPAIR_FROM_PEM diff --git a/bindings/kotlin/examples/AddressFromMnemonic.kt b/bindings/kotlin/examples/AddressFromMnemonic.kt index 333e3b536..fcdd8d9e5 100644 --- a/bindings/kotlin/examples/AddressFromMnemonic.kt +++ b/bindings/kotlin/examples/AddressFromMnemonic.kt @@ -22,7 +22,7 @@ fun main() { println("Public Key With Flag: ${base64Encode(flaggedPublicKeyEd25519)}") println("Address: ${addressEd25519.toHex()}") - val privateKeySecp256k1 = Secp256k1PrivateKey.fromMnemonic(MNEMONIC) + val privateKeySecp256k1 = Secp256k1PrivateKey.fromMnemonic(MNEMONIC, 1uL) val privateKeySecp256k1Bech32 = privateKeySecp256k1.toBech32() val publicKeySecp256k1 = privateKeySecp256k1.publicKey() val flaggedPublicKeySecp256k1 = publicKeySecp256k1.toFlaggedBytes() @@ -34,7 +34,8 @@ fun main() { println("Public Key With Flag: ${base64Encode(flaggedPublicKeySecp256k1)}") println("Address: ${addressSecp256k1.toHex()}") - val privateKeySecp256r1 = Secp256r1PrivateKey.fromMnemonic(MNEMONIC) + val privateKeySecp256r1 = + Secp256r1PrivateKey.fromMnemonicWithPath(MNEMONIC, "m/74'/4218'/0'/0/2") val privateKeySecp256r1Bech32 = privateKeySecp256r1.toBech32() val publicKeySecp256r1 = privateKeySecp256r1.publicKey() val flaggedPublicKeySecp256r1 = publicKeySecp256r1.toFlaggedBytes() diff --git a/bindings/kotlin/lib/iota_sdk/iota_sdk_ffi.kt b/bindings/kotlin/lib/iota_sdk/iota_sdk_ffi.kt index 5f07d32e0..664158804 100644 --- a/bindings/kotlin/lib/iota_sdk/iota_sdk_ffi.kt +++ b/bindings/kotlin/lib/iota_sdk/iota_sdk_ffi.kt @@ -2908,6 +2908,10 @@ internal interface UniffiForeignFutureCompleteVoid : com.sun.jna.Callback { + + + + @@ -4430,6 +4434,8 @@ fun uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_der( ): Short fun uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_mnemonic( ): Short +fun uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_mnemonic_with_path( +): Short fun uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_pem( ): Short fun uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_generate( @@ -4708,6 +4714,8 @@ fun uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_der( ): Short fun uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_mnemonic( ): Short +fun uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_mnemonic_with_path( +): Short fun uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_pem( ): Short fun uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_generate( @@ -4740,6 +4748,8 @@ fun uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_der( ): Short fun uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_mnemonic( ): Short +fun uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_mnemonic_with_path( +): Short fun uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_pem( ): Short fun uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_generate( @@ -4774,8 +4784,6 @@ fun uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_der( ): Short fun uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_ed25519( ): Short -fun uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_mnemonic( -): Short fun uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_pem( ): Short fun uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_secp256k1( @@ -5263,7 +5271,9 @@ fun uniffi_iota_sdk_ffi_fn_constructor_ed25519privatekey_from_bech32(`value`: Ru ): Pointer fun uniffi_iota_sdk_ffi_fn_constructor_ed25519privatekey_from_der(`bytes`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): Pointer -fun uniffi_iota_sdk_ffi_fn_constructor_ed25519privatekey_from_mnemonic(`phrase`: RustBuffer.ByValue,`password`: RustBuffer.ByValue,`path`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, +fun uniffi_iota_sdk_ffi_fn_constructor_ed25519privatekey_from_mnemonic(`phrase`: RustBuffer.ByValue,`accountIndex`: Long,`password`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, +): Pointer +fun uniffi_iota_sdk_ffi_fn_constructor_ed25519privatekey_from_mnemonic_with_path(`phrase`: RustBuffer.ByValue,`path`: RustBuffer.ByValue,`password`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): Pointer fun uniffi_iota_sdk_ffi_fn_constructor_ed25519privatekey_from_pem(`s`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): Pointer @@ -6141,7 +6151,9 @@ fun uniffi_iota_sdk_ffi_fn_constructor_secp256k1privatekey_from_bech32(`value`: ): Pointer fun uniffi_iota_sdk_ffi_fn_constructor_secp256k1privatekey_from_der(`bytes`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): Pointer -fun uniffi_iota_sdk_ffi_fn_constructor_secp256k1privatekey_from_mnemonic(`phrase`: RustBuffer.ByValue,`password`: RustBuffer.ByValue,`path`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, +fun uniffi_iota_sdk_ffi_fn_constructor_secp256k1privatekey_from_mnemonic(`phrase`: RustBuffer.ByValue,`accountIndex`: Long,`password`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, +): Pointer +fun uniffi_iota_sdk_ffi_fn_constructor_secp256k1privatekey_from_mnemonic_with_path(`phrase`: RustBuffer.ByValue,`path`: RustBuffer.ByValue,`password`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): Pointer fun uniffi_iota_sdk_ffi_fn_constructor_secp256k1privatekey_from_pem(`s`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): Pointer @@ -6239,7 +6251,9 @@ fun uniffi_iota_sdk_ffi_fn_constructor_secp256r1privatekey_from_bech32(`value`: ): Pointer fun uniffi_iota_sdk_ffi_fn_constructor_secp256r1privatekey_from_der(`bytes`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): Pointer -fun uniffi_iota_sdk_ffi_fn_constructor_secp256r1privatekey_from_mnemonic(`phrase`: RustBuffer.ByValue,`password`: RustBuffer.ByValue,`path`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, +fun uniffi_iota_sdk_ffi_fn_constructor_secp256r1privatekey_from_mnemonic(`phrase`: RustBuffer.ByValue,`accountIndex`: Long,`password`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, +): Pointer +fun uniffi_iota_sdk_ffi_fn_constructor_secp256r1privatekey_from_mnemonic_with_path(`phrase`: RustBuffer.ByValue,`path`: RustBuffer.ByValue,`password`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): Pointer fun uniffi_iota_sdk_ffi_fn_constructor_secp256r1privatekey_from_pem(`s`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): Pointer @@ -6341,8 +6355,6 @@ fun uniffi_iota_sdk_ffi_fn_constructor_simplekeypair_from_der(`bytes`: RustBuffe ): Pointer fun uniffi_iota_sdk_ffi_fn_constructor_simplekeypair_from_ed25519(`keypair`: Pointer,uniffi_out_err: UniffiRustCallStatus, ): Pointer -fun uniffi_iota_sdk_ffi_fn_constructor_simplekeypair_from_mnemonic(`scheme`: RustBuffer.ByValue,`phrase`: RustBuffer.ByValue,`password`: RustBuffer.ByValue,`path`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, -): Pointer fun uniffi_iota_sdk_ffi_fn_constructor_simplekeypair_from_pem(`s`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): Pointer fun uniffi_iota_sdk_ffi_fn_constructor_simplekeypair_from_secp256k1(`keypair`: Pointer,uniffi_out_err: UniffiRustCallStatus, @@ -9741,7 +9753,10 @@ private fun uniffiCheckApiChecksums(lib: IntegrityCheckingUniffiLib) { if (lib.uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_der() != 42838.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_mnemonic() != 52060.toShort()) { + if (lib.uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_mnemonic() != 55789.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_mnemonic_with_path() != 15255.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } if (lib.uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_pem() != 53776.toShort()) { @@ -10158,7 +10173,10 @@ private fun uniffiCheckApiChecksums(lib: IntegrityCheckingUniffiLib) { if (lib.uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_der() != 45448.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_mnemonic() != 27698.toShort()) { + if (lib.uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_mnemonic() != 33082.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_mnemonic_with_path() != 7431.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } if (lib.uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_pem() != 20937.toShort()) { @@ -10206,7 +10224,10 @@ private fun uniffiCheckApiChecksums(lib: IntegrityCheckingUniffiLib) { if (lib.uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_der() != 63595.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_mnemonic() != 62413.toShort()) { + if (lib.uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_mnemonic() != 57849.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_mnemonic_with_path() != 7709.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } if (lib.uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_pem() != 28166.toShort()) { @@ -10260,9 +10281,6 @@ private fun uniffiCheckApiChecksums(lib: IntegrityCheckingUniffiLib) { if (lib.uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_ed25519() != 22142.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_mnemonic() != 10406.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } if (lib.uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_pem() != 2041.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } @@ -18288,11 +18306,26 @@ open class Ed25519PrivateKey: Disposable, AutoCloseable, Ed25519PrivateKeyInterf /** * Construct the private key from a mnemonic phrase */ - @Throws(SdkFfiException::class) fun `fromMnemonic`(`phrase`: kotlin.String, `password`: kotlin.String? = null, `path`: kotlin.String? = null): Ed25519PrivateKey { + @Throws(SdkFfiException::class) fun `fromMnemonic`(`phrase`: kotlin.String, `accountIndex`: kotlin.ULong = 0uL, `password`: kotlin.String = ""): Ed25519PrivateKey { return FfiConverterTypeEd25519PrivateKey.lift( uniffiRustCallWithError(SdkFfiException) { _status -> UniffiLib.INSTANCE.uniffi_iota_sdk_ffi_fn_constructor_ed25519privatekey_from_mnemonic( - FfiConverterString.lower(`phrase`),FfiConverterOptionalString.lower(`password`),FfiConverterOptionalString.lower(`path`),_status) + FfiConverterString.lower(`phrase`),FfiConverterULong.lower(`accountIndex`),FfiConverterString.lower(`password`),_status) +} + ) + } + + + + /** + * Create an instance from a mnemonic phrase and a derivation path like + * `"m/44'/4218'/0'/0'/0'"` + */ + @Throws(SdkFfiException::class) fun `fromMnemonicWithPath`(`phrase`: kotlin.String, `path`: kotlin.String, `password`: kotlin.String = ""): Ed25519PrivateKey { + return FfiConverterTypeEd25519PrivateKey.lift( + uniffiRustCallWithError(SdkFfiException) { _status -> + UniffiLib.INSTANCE.uniffi_iota_sdk_ffi_fn_constructor_ed25519privatekey_from_mnemonic_with_path( + FfiConverterString.lower(`phrase`),FfiConverterString.lower(`path`),FfiConverterString.lower(`password`),_status) } ) } @@ -34698,11 +34731,26 @@ open class Secp256k1PrivateKey: Disposable, AutoCloseable, Secp256k1PrivateKeyIn /** * Construct the private key from a mnemonic phrase */ - @Throws(SdkFfiException::class) fun `fromMnemonic`(`phrase`: kotlin.String, `password`: kotlin.String? = null, `path`: kotlin.String? = null): Secp256k1PrivateKey { + @Throws(SdkFfiException::class) fun `fromMnemonic`(`phrase`: kotlin.String, `accountIndex`: kotlin.ULong = 0uL, `password`: kotlin.String = ""): Secp256k1PrivateKey { return FfiConverterTypeSecp256k1PrivateKey.lift( uniffiRustCallWithError(SdkFfiException) { _status -> UniffiLib.INSTANCE.uniffi_iota_sdk_ffi_fn_constructor_secp256k1privatekey_from_mnemonic( - FfiConverterString.lower(`phrase`),FfiConverterOptionalString.lower(`password`),FfiConverterOptionalString.lower(`path`),_status) + FfiConverterString.lower(`phrase`),FfiConverterULong.lower(`accountIndex`),FfiConverterString.lower(`password`),_status) +} + ) + } + + + + /** + * Create an instance from a mnemonic phrase and a derivation path like + * `"m/54'/4218'/0'/0/0"` + */ + @Throws(SdkFfiException::class) fun `fromMnemonicWithPath`(`phrase`: kotlin.String, `path`: kotlin.String, `password`: kotlin.String = ""): Secp256k1PrivateKey { + return FfiConverterTypeSecp256k1PrivateKey.lift( + uniffiRustCallWithError(SdkFfiException) { _status -> + UniffiLib.INSTANCE.uniffi_iota_sdk_ffi_fn_constructor_secp256k1privatekey_from_mnemonic_with_path( + FfiConverterString.lower(`phrase`),FfiConverterString.lower(`path`),FfiConverterString.lower(`password`),_status) } ) } @@ -36459,11 +36507,26 @@ open class Secp256r1PrivateKey: Disposable, AutoCloseable, Secp256r1PrivateKeyIn /** * Construct the private key from a mnemonic phrase */ - @Throws(SdkFfiException::class) fun `fromMnemonic`(`phrase`: kotlin.String, `password`: kotlin.String? = null, `path`: kotlin.String? = null): Secp256r1PrivateKey { + @Throws(SdkFfiException::class) fun `fromMnemonic`(`phrase`: kotlin.String, `accountIndex`: kotlin.ULong = 0uL, `password`: kotlin.String = ""): Secp256r1PrivateKey { return FfiConverterTypeSecp256r1PrivateKey.lift( uniffiRustCallWithError(SdkFfiException) { _status -> UniffiLib.INSTANCE.uniffi_iota_sdk_ffi_fn_constructor_secp256r1privatekey_from_mnemonic( - FfiConverterString.lower(`phrase`),FfiConverterOptionalString.lower(`password`),FfiConverterOptionalString.lower(`path`),_status) + FfiConverterString.lower(`phrase`),FfiConverterULong.lower(`accountIndex`),FfiConverterString.lower(`password`),_status) +} + ) + } + + + + /** + * Create an instance from a mnemonic phrase and a derivation path like + * `"m/74'/4218'/0'/0/0"` + */ + @Throws(SdkFfiException::class) fun `fromMnemonicWithPath`(`phrase`: kotlin.String, `path`: kotlin.String, `password`: kotlin.String = ""): Secp256r1PrivateKey { + return FfiConverterTypeSecp256r1PrivateKey.lift( + uniffiRustCallWithError(SdkFfiException) { _status -> + UniffiLib.INSTANCE.uniffi_iota_sdk_ffi_fn_constructor_secp256r1privatekey_from_mnemonic_with_path( + FfiConverterString.lower(`phrase`),FfiConverterString.lower(`path`),FfiConverterString.lower(`password`),_status) } ) } @@ -38184,21 +38247,6 @@ open class SimpleKeypair: Disposable, AutoCloseable, SimpleKeypairInterface - /** - * Construct the private key from a mnemonic phrase and the signature - * scheme - */ - @Throws(SdkFfiException::class) fun `fromMnemonic`(`scheme`: SignatureScheme, `phrase`: kotlin.String, `password`: kotlin.String? = null, `path`: kotlin.String? = null): SimpleKeypair { - return FfiConverterTypeSimpleKeypair.lift( - uniffiRustCallWithError(SdkFfiException) { _status -> - UniffiLib.INSTANCE.uniffi_iota_sdk_ffi_fn_constructor_simplekeypair_from_mnemonic( - FfiConverterTypeSignatureScheme.lower(`scheme`),FfiConverterString.lower(`phrase`),FfiConverterOptionalString.lower(`password`),FfiConverterOptionalString.lower(`path`),_status) -} - ) - } - - - /** * Deserialize PKCS#8-encoded private key from PEM. */ diff --git a/bindings/python/examples/address_from_mnemonic.py b/bindings/python/examples/address_from_mnemonic.py index adadc4020..63dde6c12 100644 --- a/bindings/python/examples/address_from_mnemonic.py +++ b/bindings/python/examples/address_from_mnemonic.py @@ -19,7 +19,7 @@ def main(): print(f"Public Key With Flag: {base64_encode(flagged_public_key)}") print(f"Address: {address.to_hex()}") - private_key = Secp256k1PrivateKey.from_mnemonic(MNEMONIC) + private_key = Secp256k1PrivateKey.from_mnemonic(MNEMONIC, 1) private_key_bech32 = private_key.to_bech32() public_key = private_key.public_key() flagged_public_key = public_key.to_flagged_bytes() @@ -31,7 +31,7 @@ def main(): print(f"Public Key With Flag: {base64_encode(flagged_public_key)}") print(f"Address: {address.to_hex()}") - private_key = Secp256r1PrivateKey.from_mnemonic(MNEMONIC) + private_key = Secp256r1PrivateKey.from_mnemonic(MNEMONIC, "m/74'/4218'/0'/0/2") private_key_bech32 = private_key.to_bech32() public_key = private_key.public_key() flagged_public_key = public_key.to_flagged_bytes() diff --git a/bindings/python/lib/iota_sdk_ffi.py b/bindings/python/lib/iota_sdk_ffi.py index 6cd61beb5..18e9cb212 100644 --- a/bindings/python/lib/iota_sdk_ffi.py +++ b/bindings/python/lib/iota_sdk_ffi.py @@ -1961,7 +1961,9 @@ def _uniffi_check_api_checksums(lib): raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") if lib.uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_der() != 42838: raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - if lib.uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_mnemonic() != 52060: + if lib.uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_mnemonic() != 55789: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_mnemonic_with_path() != 15255: raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") if lib.uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_pem() != 53776: raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") @@ -2239,7 +2241,9 @@ def _uniffi_check_api_checksums(lib): raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") if lib.uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_der() != 45448: raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - if lib.uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_mnemonic() != 27698: + if lib.uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_mnemonic() != 33082: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_mnemonic_with_path() != 7431: raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") if lib.uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_pem() != 20937: raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") @@ -2271,7 +2275,9 @@ def _uniffi_check_api_checksums(lib): raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") if lib.uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_der() != 63595: raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - if lib.uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_mnemonic() != 62413: + if lib.uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_mnemonic() != 57849: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_mnemonic_with_path() != 7709: raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") if lib.uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_pem() != 28166: raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") @@ -2307,8 +2313,6 @@ def _uniffi_check_api_checksums(lib): raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") if lib.uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_ed25519() != 22142: raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - if lib.uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_mnemonic() != 10406: - raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") if lib.uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_pem() != 2041: raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") if lib.uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_secp256k1() != 46546: @@ -3358,11 +3362,18 @@ class _UniffiForeignFutureStructVoid(ctypes.Structure): _UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_ed25519privatekey_from_der.restype = ctypes.c_void_p _UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_ed25519privatekey_from_mnemonic.argtypes = ( _UniffiRustBuffer, - _UniffiRustBuffer, + ctypes.c_uint64, _UniffiRustBuffer, ctypes.POINTER(_UniffiRustCallStatus), ) _UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_ed25519privatekey_from_mnemonic.restype = ctypes.c_void_p +_UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_ed25519privatekey_from_mnemonic_with_path.argtypes = ( + _UniffiRustBuffer, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_ed25519privatekey_from_mnemonic_with_path.restype = ctypes.c_void_p _UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_ed25519privatekey_from_pem.argtypes = ( _UniffiRustBuffer, ctypes.POINTER(_UniffiRustCallStatus), @@ -5619,11 +5630,18 @@ class _UniffiForeignFutureStructVoid(ctypes.Structure): _UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_secp256k1privatekey_from_der.restype = ctypes.c_void_p _UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_secp256k1privatekey_from_mnemonic.argtypes = ( _UniffiRustBuffer, - _UniffiRustBuffer, + ctypes.c_uint64, _UniffiRustBuffer, ctypes.POINTER(_UniffiRustCallStatus), ) _UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_secp256k1privatekey_from_mnemonic.restype = ctypes.c_void_p +_UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_secp256k1privatekey_from_mnemonic_with_path.argtypes = ( + _UniffiRustBuffer, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_secp256k1privatekey_from_mnemonic_with_path.restype = ctypes.c_void_p _UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_secp256k1privatekey_from_pem.argtypes = ( _UniffiRustBuffer, ctypes.POINTER(_UniffiRustCallStatus), @@ -5875,11 +5893,18 @@ class _UniffiForeignFutureStructVoid(ctypes.Structure): _UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_secp256r1privatekey_from_der.restype = ctypes.c_void_p _UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_secp256r1privatekey_from_mnemonic.argtypes = ( _UniffiRustBuffer, - _UniffiRustBuffer, + ctypes.c_uint64, _UniffiRustBuffer, ctypes.POINTER(_UniffiRustCallStatus), ) _UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_secp256r1privatekey_from_mnemonic.restype = ctypes.c_void_p +_UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_secp256r1privatekey_from_mnemonic_with_path.argtypes = ( + _UniffiRustBuffer, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_secp256r1privatekey_from_mnemonic_with_path.restype = ctypes.c_void_p _UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_secp256r1privatekey_from_pem.argtypes = ( _UniffiRustBuffer, ctypes.POINTER(_UniffiRustCallStatus), @@ -6139,14 +6164,6 @@ class _UniffiForeignFutureStructVoid(ctypes.Structure): ctypes.POINTER(_UniffiRustCallStatus), ) _UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_simplekeypair_from_ed25519.restype = ctypes.c_void_p -_UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_simplekeypair_from_mnemonic.argtypes = ( - _UniffiRustBuffer, - _UniffiRustBuffer, - _UniffiRustBuffer, - _UniffiRustBuffer, - ctypes.POINTER(_UniffiRustCallStatus), -) -_UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_simplekeypair_from_mnemonic.restype = ctypes.c_void_p _UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_simplekeypair_from_pem.argtypes = ( _UniffiRustBuffer, ctypes.POINTER(_UniffiRustCallStatus), @@ -11299,6 +11316,9 @@ class _UniffiForeignFutureStructVoid(ctypes.Structure): _UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_mnemonic.argtypes = ( ) _UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_mnemonic.restype = ctypes.c_uint16 +_UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_mnemonic_with_path.argtypes = ( +) +_UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_mnemonic_with_path.restype = ctypes.c_uint16 _UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_pem.argtypes = ( ) _UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_ed25519privatekey_from_pem.restype = ctypes.c_uint16 @@ -11716,6 +11736,9 @@ class _UniffiForeignFutureStructVoid(ctypes.Structure): _UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_mnemonic.argtypes = ( ) _UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_mnemonic.restype = ctypes.c_uint16 +_UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_mnemonic_with_path.argtypes = ( +) +_UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_mnemonic_with_path.restype = ctypes.c_uint16 _UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_pem.argtypes = ( ) _UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_secp256k1privatekey_from_pem.restype = ctypes.c_uint16 @@ -11764,6 +11787,9 @@ class _UniffiForeignFutureStructVoid(ctypes.Structure): _UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_mnemonic.argtypes = ( ) _UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_mnemonic.restype = ctypes.c_uint16 +_UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_mnemonic_with_path.argtypes = ( +) +_UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_mnemonic_with_path.restype = ctypes.c_uint16 _UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_pem.argtypes = ( ) _UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_secp256r1privatekey_from_pem.restype = ctypes.c_uint16 @@ -11815,9 +11841,6 @@ class _UniffiForeignFutureStructVoid(ctypes.Structure): _UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_ed25519.argtypes = ( ) _UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_ed25519.restype = ctypes.c_uint16 -_UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_mnemonic.argtypes = ( -) -_UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_mnemonic.restype = ctypes.c_uint16 _UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_pem.argtypes = ( ) _UniffiLib.uniffi_iota_sdk_ffi_checksum_constructor_simplekeypair_from_pem.restype = ctypes.c_uint16 @@ -28679,26 +28702,48 @@ def from_der(cls, bytes: "bytes"): return cls._make_instance_(pointer) @classmethod - def from_mnemonic(cls, phrase: "str",password: "typing.Union[object, typing.Optional[str]]" = _DEFAULT,path: "typing.Union[object, typing.Optional[str]]" = _DEFAULT): + def from_mnemonic(cls, phrase: "str",account_index: "typing.Union[object, int]" = _DEFAULT,password: "typing.Union[object, str]" = _DEFAULT): """ Construct the private key from a mnemonic phrase """ _UniffiConverterString.check_lower(phrase) - if password is _DEFAULT: - password = None - _UniffiConverterOptionalString.check_lower(password) + if account_index is _DEFAULT: + account_index = 0 + _UniffiConverterUInt64.check_lower(account_index) - if path is _DEFAULT: - path = None - _UniffiConverterOptionalString.check_lower(path) + if password is _DEFAULT: + password = "" + _UniffiConverterString.check_lower(password) # Call the (fallible) function before creating any half-baked object instances. pointer = _uniffi_rust_call_with_error(_UniffiConverterTypeSdkFfiError,_UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_ed25519privatekey_from_mnemonic, _UniffiConverterString.lower(phrase), - _UniffiConverterOptionalString.lower(password), - _UniffiConverterOptionalString.lower(path)) + _UniffiConverterUInt64.lower(account_index), + _UniffiConverterString.lower(password)) + return cls._make_instance_(pointer) + + @classmethod + def from_mnemonic_with_path(cls, phrase: "str",path: "str",password: "typing.Union[object, str]" = _DEFAULT): + """ + Create an instance from a mnemonic phrase and a derivation path like + `"m/44'/4218'/0'/0'/0'"` + """ + + _UniffiConverterString.check_lower(phrase) + + _UniffiConverterString.check_lower(path) + + if password is _DEFAULT: + password = "" + _UniffiConverterString.check_lower(password) + + # Call the (fallible) function before creating any half-baked object instances. + pointer = _uniffi_rust_call_with_error(_UniffiConverterTypeSdkFfiError,_UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_ed25519privatekey_from_mnemonic_with_path, + _UniffiConverterString.lower(phrase), + _UniffiConverterString.lower(path), + _UniffiConverterString.lower(password)) return cls._make_instance_(pointer) @classmethod @@ -37737,26 +37782,48 @@ def from_der(cls, bytes: "bytes"): return cls._make_instance_(pointer) @classmethod - def from_mnemonic(cls, phrase: "str",password: "typing.Union[object, typing.Optional[str]]" = _DEFAULT,path: "typing.Union[object, typing.Optional[str]]" = _DEFAULT): + def from_mnemonic(cls, phrase: "str",account_index: "typing.Union[object, int]" = _DEFAULT,password: "typing.Union[object, str]" = _DEFAULT): """ Construct the private key from a mnemonic phrase """ _UniffiConverterString.check_lower(phrase) - if password is _DEFAULT: - password = None - _UniffiConverterOptionalString.check_lower(password) + if account_index is _DEFAULT: + account_index = 0 + _UniffiConverterUInt64.check_lower(account_index) - if path is _DEFAULT: - path = None - _UniffiConverterOptionalString.check_lower(path) + if password is _DEFAULT: + password = "" + _UniffiConverterString.check_lower(password) # Call the (fallible) function before creating any half-baked object instances. pointer = _uniffi_rust_call_with_error(_UniffiConverterTypeSdkFfiError,_UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_secp256k1privatekey_from_mnemonic, _UniffiConverterString.lower(phrase), - _UniffiConverterOptionalString.lower(password), - _UniffiConverterOptionalString.lower(path)) + _UniffiConverterUInt64.lower(account_index), + _UniffiConverterString.lower(password)) + return cls._make_instance_(pointer) + + @classmethod + def from_mnemonic_with_path(cls, phrase: "str",path: "str",password: "typing.Union[object, str]" = _DEFAULT): + """ + Create an instance from a mnemonic phrase and a derivation path like + `"m/54'/4218'/0'/0/0"` + """ + + _UniffiConverterString.check_lower(phrase) + + _UniffiConverterString.check_lower(path) + + if password is _DEFAULT: + password = "" + _UniffiConverterString.check_lower(password) + + # Call the (fallible) function before creating any half-baked object instances. + pointer = _uniffi_rust_call_with_error(_UniffiConverterTypeSdkFfiError,_UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_secp256k1privatekey_from_mnemonic_with_path, + _UniffiConverterString.lower(phrase), + _UniffiConverterString.lower(path), + _UniffiConverterString.lower(password)) return cls._make_instance_(pointer) @classmethod @@ -38596,26 +38663,48 @@ def from_der(cls, bytes: "bytes"): return cls._make_instance_(pointer) @classmethod - def from_mnemonic(cls, phrase: "str",password: "typing.Union[object, typing.Optional[str]]" = _DEFAULT,path: "typing.Union[object, typing.Optional[str]]" = _DEFAULT): + def from_mnemonic(cls, phrase: "str",account_index: "typing.Union[object, int]" = _DEFAULT,password: "typing.Union[object, str]" = _DEFAULT): """ Construct the private key from a mnemonic phrase """ _UniffiConverterString.check_lower(phrase) - if password is _DEFAULT: - password = None - _UniffiConverterOptionalString.check_lower(password) + if account_index is _DEFAULT: + account_index = 0 + _UniffiConverterUInt64.check_lower(account_index) - if path is _DEFAULT: - path = None - _UniffiConverterOptionalString.check_lower(path) + if password is _DEFAULT: + password = "" + _UniffiConverterString.check_lower(password) # Call the (fallible) function before creating any half-baked object instances. pointer = _uniffi_rust_call_with_error(_UniffiConverterTypeSdkFfiError,_UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_secp256r1privatekey_from_mnemonic, _UniffiConverterString.lower(phrase), - _UniffiConverterOptionalString.lower(password), - _UniffiConverterOptionalString.lower(path)) + _UniffiConverterUInt64.lower(account_index), + _UniffiConverterString.lower(password)) + return cls._make_instance_(pointer) + + @classmethod + def from_mnemonic_with_path(cls, phrase: "str",path: "str",password: "typing.Union[object, str]" = _DEFAULT): + """ + Create an instance from a mnemonic phrase and a derivation path like + `"m/74'/4218'/0'/0/0"` + """ + + _UniffiConverterString.check_lower(phrase) + + _UniffiConverterString.check_lower(path) + + if password is _DEFAULT: + password = "" + _UniffiConverterString.check_lower(password) + + # Call the (fallible) function before creating any half-baked object instances. + pointer = _uniffi_rust_call_with_error(_UniffiConverterTypeSdkFfiError,_UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_secp256r1privatekey_from_mnemonic_with_path, + _UniffiConverterString.lower(phrase), + _UniffiConverterString.lower(path), + _UniffiConverterString.lower(password)) return cls._make_instance_(pointer) @classmethod @@ -39475,33 +39564,6 @@ def from_ed25519(cls, keypair: "Ed25519PrivateKey"): _UniffiConverterTypeEd25519PrivateKey.lower(keypair)) return cls._make_instance_(pointer) - @classmethod - def from_mnemonic(cls, scheme: "SignatureScheme",phrase: "str",password: "typing.Union[object, typing.Optional[str]]" = _DEFAULT,path: "typing.Union[object, typing.Optional[str]]" = _DEFAULT): - """ - Construct the private key from a mnemonic phrase and the signature - scheme - """ - - _UniffiConverterTypeSignatureScheme.check_lower(scheme) - - _UniffiConverterString.check_lower(phrase) - - if password is _DEFAULT: - password = None - _UniffiConverterOptionalString.check_lower(password) - - if path is _DEFAULT: - path = None - _UniffiConverterOptionalString.check_lower(path) - - # Call the (fallible) function before creating any half-baked object instances. - pointer = _uniffi_rust_call_with_error(_UniffiConverterTypeSdkFfiError,_UniffiLib.uniffi_iota_sdk_ffi_fn_constructor_simplekeypair_from_mnemonic, - _UniffiConverterTypeSignatureScheme.lower(scheme), - _UniffiConverterString.lower(phrase), - _UniffiConverterOptionalString.lower(password), - _UniffiConverterOptionalString.lower(path)) - return cls._make_instance_(pointer) - @classmethod def from_pem(cls, s: "str"): """ diff --git a/crates/iota-sdk-crypto/src/ed25519.rs b/crates/iota-sdk-crypto/src/ed25519.rs index d7c81a5f1..6c47508b8 100644 --- a/crates/iota-sdk-crypto/src/ed25519.rs +++ b/crates/iota-sdk-crypto/src/ed25519.rs @@ -142,20 +142,33 @@ impl crate::FromMnemonic for Ed25519PrivateKey { fn from_mnemonic( phrase: &str, + account_index: impl Into>, password: impl Into>, - path: impl Into>, - ) -> Result { + ) -> Result + where + Self: Sized, + { + let path = format!( + "m/{}'/{}'/0'/0'/{}'", + crate::DERIVATION_PATH_PURPOSE_ED25519, + crate::DERIVATION_PATH_COIN_TYPE, + account_index.into().unwrap_or_default() + ); + Self::from_mnemonic_with_path(phrase, path, password) + } + + fn from_mnemonic_with_path( + phrase: &str, + path: String, + password: impl Into>, + ) -> Result + where + Self: Sized, + { use std::str::FromStr; let mnemonic = bip39::Mnemonic::parse_in_normalized(bip39::Language::English, phrase)?; let seed = mnemonic.to_seed(password.into().unwrap_or_default()); - let path = path.into().unwrap_or_else(|| { - format!( - "m/{}'/{}'/0'/0'/0'", - crate::DERIVATION_PATH_PURPOSE_ED25519, - crate::DERIVATION_PATH_COIN_TYPE - ) - }); let path = bip32::DerivationPath::from_str(&path)? .into_iter() .map(|c| c.0) diff --git a/crates/iota-sdk-crypto/src/lib.rs b/crates/iota-sdk-crypto/src/lib.rs index b5ba12587..e40ef7699 100644 --- a/crates/iota-sdk-crypto/src/lib.rs +++ b/crates/iota-sdk-crypto/src/lib.rs @@ -332,8 +332,20 @@ pub trait FromMnemonic { /// Create an instance from a mnemonic phrase fn from_mnemonic( phrase: &str, + account_index: impl Into>, + password: impl Into>, + ) -> Result + where + Self: Sized; + + /// Create an instance from a mnemonic phrase and a derivation path like: + /// - Ed25519: `"m/44'/4218'/0'/0'/0'"` + /// - Secp256k1: `"m/54'/4218'/0'/0/0"` + /// - Secp256r1: `"m/74'/4218'/0'/0/0"` + fn from_mnemonic_with_path( + phrase: &str, + path: String, password: impl Into>, - path: impl Into>, ) -> Result where Self: Sized; diff --git a/crates/iota-sdk-crypto/src/secp256k1.rs b/crates/iota-sdk-crypto/src/secp256k1.rs index 13cbeb65c..39004b2bf 100644 --- a/crates/iota-sdk-crypto/src/secp256k1.rs +++ b/crates/iota-sdk-crypto/src/secp256k1.rs @@ -147,22 +147,35 @@ impl crate::FromMnemonic for Secp256k1PrivateKey { fn from_mnemonic( phrase: &str, + account_index: impl Into>, password: impl Into>, - path: impl Into>, - ) -> Result { + ) -> Result + where + Self: Sized, + { + let path = format!( + "m/{}'/{}'/0'/0/{}", + crate::DERIVATION_PATH_PURPOSE_SECP256K1, + crate::DERIVATION_PATH_COIN_TYPE, + account_index.into().unwrap_or_default() + ); + Self::from_mnemonic_with_path(phrase, path, password) + } + + fn from_mnemonic_with_path( + phrase: &str, + path: String, + password: impl Into>, + ) -> Result + where + Self: Sized, + { use std::str::FromStr; use crate::ToFromBytes; let mnemonic = bip39::Mnemonic::parse_in_normalized(bip39::Language::English, phrase)?; let seed = mnemonic.to_seed(password.into().unwrap_or_default()); - let path = path.into().unwrap_or_else(|| { - format!( - "m/{}'/{}'/0'/0/0", - crate::DERIVATION_PATH_PURPOSE_SECP256K1, - crate::DERIVATION_PATH_COIN_TYPE - ) - }); let child_xprv = bip32::XPrv::derive_from_path(seed, &bip32::DerivationPath::from_str(&path)?)?; Self::from_bytes(&child_xprv.private_key().to_bytes()) diff --git a/crates/iota-sdk-crypto/src/secp256r1.rs b/crates/iota-sdk-crypto/src/secp256r1.rs index 486f6e723..01df87490 100644 --- a/crates/iota-sdk-crypto/src/secp256r1.rs +++ b/crates/iota-sdk-crypto/src/secp256r1.rs @@ -147,23 +147,35 @@ impl crate::FromMnemonic for Secp256r1PrivateKey { fn from_mnemonic( phrase: &str, + account_index: impl Into>, password: impl Into>, - path: impl Into>, - ) -> Result { + ) -> Result + where + Self: Sized, + { + let path = format!( + "m/{}'/{}'/0'/0/{}", + crate::DERIVATION_PATH_PURPOSE_SECP256R1, + crate::DERIVATION_PATH_COIN_TYPE, + account_index.into().unwrap_or_default() + ); + Self::from_mnemonic_with_path(phrase, path, password) + } + + fn from_mnemonic_with_path( + phrase: &str, + path: String, + password: impl Into>, + ) -> Result + where + Self: Sized, + { use std::str::FromStr; use crate::ToFromBytes; let mnemonic = bip39::Mnemonic::parse_in_normalized(bip39::Language::English, phrase)?; let seed = mnemonic.to_seed(password.into().unwrap_or_default()); - - let path = path.into().unwrap_or_else(|| { - format!( - "m/{}'/{}'/0'/0/0", - crate::DERIVATION_PATH_PURPOSE_SECP256R1, - crate::DERIVATION_PATH_COIN_TYPE - ) - }); let child_xprv = bip32::XPrv::derive_from_path(seed, &bip32::DerivationPath::from_str(&path)?)?; Self::from_bytes(&child_xprv.private_key().to_bytes()) diff --git a/crates/iota-sdk-ffi/src/crypto/ed25519.rs b/crates/iota-sdk-ffi/src/crypto/ed25519.rs index 40b3076f4..8771e30da 100644 --- a/crates/iota-sdk-ffi/src/crypto/ed25519.rs +++ b/crates/iota-sdk-ffi/src/crypto/ed25519.rs @@ -90,15 +90,25 @@ impl Ed25519PrivateKey { } /// Construct the private key from a mnemonic phrase - #[uniffi::constructor(default(password = None, path = None))] - pub fn from_mnemonic( - phrase: &str, - password: Option, - path: Option, - ) -> Result { + #[uniffi::constructor(default(password = "", account_index = 0))] + pub fn from_mnemonic(phrase: &str, account_index: u64, password: String) -> Result { + Ok(iota_sdk::crypto::ed25519::Ed25519PrivateKey::from_mnemonic( + phrase, + account_index, + password, + )? + .into()) + } + + /// Create an instance from a mnemonic phrase and a derivation path like + /// `"m/44'/4218'/0'/0'/0'"` + #[uniffi::constructor(default(password = ""))] + pub fn from_mnemonic_with_path(phrase: &str, path: String, password: String) -> Result { Ok( - iota_sdk::crypto::ed25519::Ed25519PrivateKey::from_mnemonic(phrase, password, path)? - .into(), + iota_sdk::crypto::ed25519::Ed25519PrivateKey::from_mnemonic_with_path( + phrase, path, password, + )? + .into(), ) } diff --git a/crates/iota-sdk-ffi/src/crypto/secp256k1.rs b/crates/iota-sdk-ffi/src/crypto/secp256k1.rs index 557106649..a7c406a51 100644 --- a/crates/iota-sdk-ffi/src/crypto/secp256k1.rs +++ b/crates/iota-sdk-ffi/src/crypto/secp256k1.rs @@ -90,15 +90,25 @@ impl Secp256k1PrivateKey { } /// Construct the private key from a mnemonic phrase - #[uniffi::constructor(default(password = None, path = None))] - pub fn from_mnemonic( - phrase: &str, - password: Option, - path: Option, - ) -> Result { + #[uniffi::constructor(default(password = "", account_index = 0))] + pub fn from_mnemonic(phrase: &str, account_index: u64, password: String) -> Result { Ok( iota_sdk::crypto::secp256k1::Secp256k1PrivateKey::from_mnemonic( - phrase, password, path, + phrase, + account_index, + password, + )? + .into(), + ) + } + + /// Create an instance from a mnemonic phrase and a derivation path like + /// `"m/54'/4218'/0'/0/0"` + #[uniffi::constructor(default(password = ""))] + pub fn from_mnemonic_with_path(phrase: &str, path: String, password: String) -> Result { + Ok( + iota_sdk::crypto::secp256k1::Secp256k1PrivateKey::from_mnemonic_with_path( + phrase, path, password, )? .into(), ) diff --git a/crates/iota-sdk-ffi/src/crypto/secp256r1.rs b/crates/iota-sdk-ffi/src/crypto/secp256r1.rs index 254f13975..7eceeeb00 100644 --- a/crates/iota-sdk-ffi/src/crypto/secp256r1.rs +++ b/crates/iota-sdk-ffi/src/crypto/secp256r1.rs @@ -122,15 +122,25 @@ impl Secp256r1PrivateKey { } /// Construct the private key from a mnemonic phrase - #[uniffi::constructor(default(password = None, path = None))] - pub fn from_mnemonic( - phrase: &str, - password: Option, - path: Option, - ) -> Result { + #[uniffi::constructor(default(password = "", account_index = 0))] + pub fn from_mnemonic(phrase: &str, account_index: u64, password: String) -> Result { Ok( iota_sdk::crypto::secp256r1::Secp256r1PrivateKey::from_mnemonic( - phrase, password, path, + phrase, + account_index, + password, + )? + .into(), + ) + } + + /// Create an instance from a mnemonic phrase and a derivation path like + /// `"m/74'/4218'/0'/0/0"` + #[uniffi::constructor(default(password = ""))] + pub fn from_mnemonic_with_path(phrase: &str, path: String, password: String) -> Result { + Ok( + iota_sdk::crypto::secp256r1::Secp256r1PrivateKey::from_mnemonic_with_path( + phrase, path, password, )? .into(), ) diff --git a/crates/iota-sdk/examples/address_from_mnemonic.rs b/crates/iota-sdk/examples/address_from_mnemonic.rs index f95ff282f..8dbfed6ef 100644 --- a/crates/iota-sdk/examples/address_from_mnemonic.rs +++ b/crates/iota-sdk/examples/address_from_mnemonic.rs @@ -23,7 +23,7 @@ fn main() -> eyre::Result<()> { println!("Public Key With Flag: {flagged_public_key}"); println!("Address: {address}"); - let private_key = Secp256k1PrivateKey::from_mnemonic(MNEMONIC, "my_password".to_owned(), None)?; + let private_key = Secp256k1PrivateKey::from_mnemonic(MNEMONIC, 1, "my_password".to_owned())?; let private_key_bech32 = private_key.to_bech32().unwrap(); let public_key = private_key.public_key(); let flagged_public_key = Base64::encode_string(&public_key.to_flagged_bytes()); @@ -35,10 +35,10 @@ fn main() -> eyre::Result<()> { println!("Public Key With Flag: {flagged_public_key}"); println!("Address: {address}"); - let private_key = Secp256r1PrivateKey::from_mnemonic( + let private_key = Secp256r1PrivateKey::from_mnemonic_with_path( MNEMONIC, + format!("m/{DERIVATION_PATH_PURPOSE_SECP256R1}'/{DERIVATION_PATH_COIN_TYPE}'/0'/0/2"), None, - format!("m/{DERIVATION_PATH_PURPOSE_SECP256R1}'/{DERIVATION_PATH_COIN_TYPE}'/0'/0'/1'"), )?; let private_key_bech32 = private_key.to_bech32().unwrap(); let public_key = private_key.public_key(); From 3c9d251f7d7034c524947c17cb3330e7346857d4 Mon Sep 17 00:00:00 2001 From: Chloe Martin Date: Fri, 31 Oct 2025 08:53:38 +0100 Subject: [PATCH 11/12] fix python example --- bindings/python/examples/address_from_mnemonic.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bindings/python/examples/address_from_mnemonic.py b/bindings/python/examples/address_from_mnemonic.py index 63dde6c12..a5fc982d6 100644 --- a/bindings/python/examples/address_from_mnemonic.py +++ b/bindings/python/examples/address_from_mnemonic.py @@ -31,7 +31,9 @@ def main(): print(f"Public Key With Flag: {base64_encode(flagged_public_key)}") print(f"Address: {address.to_hex()}") - private_key = Secp256r1PrivateKey.from_mnemonic(MNEMONIC, "m/74'/4218'/0'/0/2") + private_key = Secp256r1PrivateKey.from_mnemonic_with_path( + MNEMONIC, "m/74'/4218'/0'/0/2" + ) private_key_bech32 = private_key.to_bech32() public_key = private_key.public_key() flagged_public_key = public_key.to_flagged_bytes() From 5cb702948c1a2f389936853ae691556a8b0049aa Mon Sep 17 00:00:00 2001 From: Chloe Martin Date: Fri, 31 Oct 2025 11:42:01 +0100 Subject: [PATCH 12/12] use constant arrays --- crates/iota-sdk-crypto/src/ed25519.rs | 5 +++-- crates/iota-sdk-crypto/src/lib.rs | 14 +++++++++----- crates/iota-sdk-crypto/src/secp256k1.rs | 5 +++-- crates/iota-sdk-crypto/src/secp256r1.rs | 5 +++-- 4 files changed, 18 insertions(+), 11 deletions(-) diff --git a/crates/iota-sdk-crypto/src/ed25519.rs b/crates/iota-sdk-crypto/src/ed25519.rs index 6c47508b8..39f300918 100644 --- a/crates/iota-sdk-crypto/src/ed25519.rs +++ b/crates/iota-sdk-crypto/src/ed25519.rs @@ -113,10 +113,11 @@ impl Ed25519PrivateKey { impl crate::ToFromBytes for Ed25519PrivateKey { type Error = crate::PrivateKeyError; + type ByteArray = [u8; Self::LENGTH]; /// Return the raw 32-byte private key - fn to_bytes(&self) -> Vec { - self.0.to_bytes().to_vec() + fn to_bytes(&self) -> Self::ByteArray { + self.0.to_bytes() } fn from_bytes(bytes: &[u8]) -> Result { diff --git a/crates/iota-sdk-crypto/src/lib.rs b/crates/iota-sdk-crypto/src/lib.rs index e40ef7699..e86052efc 100644 --- a/crates/iota-sdk-crypto/src/lib.rs +++ b/crates/iota-sdk-crypto/src/lib.rs @@ -210,9 +210,10 @@ pub trait PrivateKeyScheme { /// Defines a type which can be constructed from bytes pub trait ToFromBytes { type Error; + type ByteArray; - /// Returns the raw bytes of this type. - fn to_bytes(&self) -> Vec; + /// Returns the raw bytes as a byte array. + fn to_bytes(&self) -> Self::ByteArray; /// Create an instance from raw bytes fn from_bytes(bytes: &[u8]) -> Result @@ -234,15 +235,18 @@ pub trait ToFromFlaggedBytes { Self: Sized; } -impl + PrivateKeyScheme> ToFromFlaggedBytes for T { +impl + PrivateKeyScheme> ToFromFlaggedBytes for T +where + T::ByteArray: AsRef<[u8]>, +{ type Error = PrivateKeyError; /// Returns the bytes with signature scheme flag prepended fn to_flagged_bytes(&self) -> Vec { let key_bytes = self.to_bytes(); - let mut bytes = Vec::with_capacity(1 + key_bytes.len()); + let mut bytes = Vec::with_capacity(1 + key_bytes.as_ref().len()); bytes.push(self.scheme().to_u8()); - bytes.extend_from_slice(&key_bytes); + bytes.extend_from_slice(key_bytes.as_ref()); bytes } diff --git a/crates/iota-sdk-crypto/src/secp256k1.rs b/crates/iota-sdk-crypto/src/secp256k1.rs index 39004b2bf..560a18f79 100644 --- a/crates/iota-sdk-crypto/src/secp256k1.rs +++ b/crates/iota-sdk-crypto/src/secp256k1.rs @@ -118,10 +118,11 @@ impl Secp256k1PrivateKey { impl crate::ToFromBytes for Secp256k1PrivateKey { type Error = crate::PrivateKeyError; + type ByteArray = [u8; Self::LENGTH]; /// Return the raw 32-byte private key - fn to_bytes(&self) -> Vec { - self.0.to_bytes().to_vec() + fn to_bytes(&self) -> Self::ByteArray { + self.0.to_bytes().into() } fn from_bytes(bytes: &[u8]) -> Result { diff --git a/crates/iota-sdk-crypto/src/secp256r1.rs b/crates/iota-sdk-crypto/src/secp256r1.rs index 01df87490..a6a0f666f 100644 --- a/crates/iota-sdk-crypto/src/secp256r1.rs +++ b/crates/iota-sdk-crypto/src/secp256r1.rs @@ -118,10 +118,11 @@ impl Secp256r1PrivateKey { impl crate::ToFromBytes for Secp256r1PrivateKey { type Error = crate::PrivateKeyError; + type ByteArray = [u8; Self::LENGTH]; /// Return the raw 32-byte private key - fn to_bytes(&self) -> Vec { - self.0.to_bytes().to_vec() + fn to_bytes(&self) -> Self::ByteArray { + self.0.to_bytes().into() } fn from_bytes(bytes: &[u8]) -> Result {