Skip to content

Commit

Permalink
Update signing interactor's IO with per factor models (#333)
Browse files Browse the repository at this point in the history
* Implement per factor source io

* Implement generic classes for io in kotlin

* Disable poly sign for device factor source kinds.

* Fixes

* Add tests for throwing host interactor in swift

* Release 1.1.102

[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]

Generated by cargo-workspaces
  • Loading branch information
micbakos-rdx authored Jan 9, 2025
1 parent 1292838 commit 7ac2d4a
Show file tree
Hide file tree
Showing 134 changed files with 2,506 additions and 727 deletions.
169 changes: 86 additions & 83 deletions Cargo.lock

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,17 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-collections.git",
"state" : {
"revision" : "671108c96644956dddcd89dd59c203dcdb36cec7",
"version" : "1.1.4"
"revision" : "94cf62b3ba8d4bed62680a282d4c25f9c63c2efb",
"version" : "1.1.0"
}
},
{
"identity" : "swift-custom-dump",
"kind" : "remoteSourceControl",
"location" : "https://github.com/pointfreeco/swift-custom-dump",
"state" : {
"revision" : "82645ec760917961cfa08c9c0c7104a57a0fa4b1",
"version" : "1.3.3"
"revision" : "f01efb26f3a192a0e88dcdb7c3c391ec2fc25d9c",
"version" : "1.3.0"
}
},
{
Expand All @@ -41,8 +41,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/pointfreeco/xctest-dynamic-overlay",
"state" : {
"revision" : "a3f634d1a409c7979cabc0a71b3f26ffa9fc8af1",
"version" : "1.4.3"
"revision" : "6f30bdba373bbd7fbfe241dddd732651f2fbd1e2",
"version" : "1.1.2"
}
}
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
public class ThrowingHostInteractor: HostInteractor {
public nonisolated(unsafe) static var shared: HostInteractor = ThrowingHostInteractor()

public func signAuth(request: SargonUniFFI.SignRequestOfAuthIntent) async throws -> SargonUniFFI.SignWithFactorsOutcomeOfAuthIntentHash {
public func signAuth(request: SargonUniFFI.SignRequestOfAuthIntent) async throws -> SargonUniFFI.SignResponseOfAuthIntentHash {
throw CommonError.SigningRejected
}

public func signTransactions(request: SargonUniFFI.SignRequestOfTransactionIntent) async throws -> SargonUniFFI.SignWithFactorsOutcomeOfTransactionIntentHash {
public func signTransactions(request: SargonUniFFI.SignRequestOfTransactionIntent) async throws -> SargonUniFFI.SignResponseOfTransactionIntentHash {
throw CommonError.SigningRejected
}

public func signSubintents(request: SargonUniFFI.SignRequestOfSubintent) async throws -> SargonUniFFI.SignWithFactorsOutcomeOfSubintentHash {
public func signSubintents(request: SargonUniFFI.SignRequestOfSubintent) async throws -> SargonUniFFI.SignResponseOfSubintentHash {
throw CommonError.SigningRejected
}

Expand Down
48 changes: 48 additions & 0 deletions apple/Tests/TestCases/System/ThrowingHostInteractorTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import Foundation
import Sargon
import SargonUniFFI
import XCTest

final class ThrowingHostInteractorTests: TestCase {
typealias SUT = ThrowingHostInteractor

func testDeriveKeysThrows() async throws {
do {
let _ = try await SUT.shared.deriveKeys(
request: SargonUniFFI.KeyDerivationRequest(derivationPurpose: .creatingNewAccount, perFactorSource: [])
)
} catch {
XCTAssertEqual(error as? CommonError, CommonError.SigningRejected)
}
}

func testSignAuthThrows() async throws {
do {
let _ = try await SUT.shared.signAuth(
request: SargonUniFFI.SignRequestOfAuthIntent(factorSourceKind: .device, perFactorSource: [])
)
} catch {
XCTAssertEqual(error as? CommonError, CommonError.SigningRejected)
}
}

func testSignTransactionsThrows() async throws {
do {
let _ = try await SUT.shared.signTransactions(
request: SargonUniFFI.SignRequestOfTransactionIntent(factorSourceKind: .device, perFactorSource: [])
)
} catch {
XCTAssertEqual(error as? CommonError, CommonError.SigningRejected)
}
}

func testSignSubintentsThrows() async throws {
do {
let _ = try await SUT.shared.signSubintents(
request: SargonUniFFI.SignRequestOfSubintent(factorSourceKind: .device, perFactorSource: [])
)
} catch {
XCTAssertEqual(error as? CommonError, CommonError.SigningRejected)
}
}
}
2 changes: 1 addition & 1 deletion crates/app/home-cards/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "home-cards"
version = "1.1.101"
version = "1.1.102"
edition = "2021"

[dependencies]
Expand Down
2 changes: 1 addition & 1 deletion crates/app/key-derivation-traits/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "key-derivation-traits"
version = "1.1.101"
version = "1.1.102"
edition = "2021"

[dependencies]
Expand Down
2 changes: 1 addition & 1 deletion crates/app/radix-connect-models/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "radix-connect-models"
version = "1.1.101"
version = "1.1.102"
edition = "2021"

[dependencies]
Expand Down
2 changes: 1 addition & 1 deletion crates/app/radix-connect/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "radix-connect"
version = "1.1.101"
version = "1.1.102"
edition = "2021"


Expand Down
2 changes: 1 addition & 1 deletion crates/app/security-center/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "security-center"
version = "1.1.101"
version = "1.1.102"
edition = "2021"

[dependencies]
Expand Down
3 changes: 2 additions & 1 deletion crates/app/signing-traits/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
[package]
name = "signing-traits"
version = "1.1.101"
version = "1.1.102"
edition = "2021"

[dependencies]
# === SARGON CRATES ===
prelude = { workspace = true }
error = { workspace = true }
ecc = { workspace = true }
enum-as-inner = { workspace = true }
core-collections = { workspace = true }
bytes = { workspace = true }
hash = { workspace = true }
Expand Down
207 changes: 207 additions & 0 deletions crates/app/signing-traits/src/host_interaction/factor_outcome.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
use crate::prelude::*;

/// The outcome of the signing process for each factor source as collected by the `SignInteractor`.
#[derive(
Clone, PartialEq, Eq, enum_as_inner::EnumAsInner, derive_more::Debug,
)]
pub enum FactorOutcome<ID: SignableID> {
/// The user successfully signed with the factor source, the associated
/// value `produced_signatures` contains the produced signatures and any relevant metadata.
#[debug("Signed: {:#?}", produced_signatures)]
Signed {
produced_signatures: IndexSet<HDSignature<ID>>,
},

/// The factor source got neglected, either due to user explicitly skipping
/// or due to failure
#[debug("Neglected")]
Neglected(NeglectedFactor),
}

impl<ID: SignableID + HasSampleValues> HasSampleValues for FactorOutcome<ID> {
fn sample() -> Self {
let signature = HDSignature::<ID>::sample();

Self::signed(IndexSet::just(signature)).unwrap()
}

fn sample_other() -> Self {
Self::skipped(FactorSourceIDFromHash::sample_other())
}
}

impl<ID: SignableID> FactorOutcome<ID> {
pub fn signed(
produced_signatures: IndexSet<HDSignature<ID>>,
) -> Result<Self> {
if produced_signatures.is_empty() {
return Err(CommonError::ExpectedNonEmptyCollection);
}

let factor_source_id = &produced_signatures
.first()
.expect("Should have at least one signature")
.factor_source_id();

if produced_signatures
.iter()
.any(|s| s.factor_source_id() != *factor_source_id)
{
return Err(CommonError::FactorOutcomeSignedFactorSourceIDMismatch);
}

Ok(FactorOutcome::Signed {
produced_signatures,
})
}

pub fn failure(factor: FactorSourceIDFromHash) -> Self {
FactorOutcome::Neglected(NeglectedFactor::new(
NeglectFactorReason::Failure,
factor,
))
}

pub fn skipped(factor: FactorSourceIDFromHash) -> Self {
FactorOutcome::Neglected(NeglectedFactor::new(
NeglectFactorReason::UserExplicitlySkipped,
factor,
))
}

pub fn irrelevant(factor: FactorSourceIDFromHash) -> Self {
FactorOutcome::Neglected(NeglectedFactor::new(
NeglectFactorReason::Irrelevant,
factor,
))
}

pub fn factor_source_id(&self) -> FactorSourceIDFromHash {
match self {
FactorOutcome::Signed {
produced_signatures,
} => {
let signature = produced_signatures
.first()
.expect("Should have at least one signature");

signature.factor_source_id()
}
FactorOutcome::Neglected(neglected_factor) => {
neglected_factor.factor_source_id()
}
}
}
}

#[cfg(test)]
mod test {
use super::*;

#[allow(clippy::upper_case_acronyms)]
type SUT = FactorOutcome<TransactionIntentHash>;

#[test]
fn equality() {
assert_eq!(SUT::sample(), SUT::sample());
assert_eq!(SUT::sample_other(), SUT::sample_other());
}

#[test]
fn inequality() {
assert_ne!(SUT::sample(), SUT::sample_other());
}

#[test]
pub fn test_signed() {
let signature = HDSignature::sample();
let signatures = IndexSet::just(signature.clone());

let sut = SUT::signed(signatures.clone()).unwrap();

assert_eq!(sut.as_signed().unwrap().clone(), signatures);
}

#[test]
pub fn test_signed_no_signatures_failure() {
let result = SUT::signed(IndexSet::new());

assert_eq!(result, Err(CommonError::ExpectedNonEmptyCollection));
}

#[test]
pub fn test_signed_different_factor_source_id_failure() {
let result = SUT::signed(
IndexSet::from([
HDSignature::fake_sign_by_looking_up_mnemonic_amongst_samples(
HDSignatureInput::new(
TransactionIntentHash::sample(),
OwnedFactorInstance::new(
AddressOfAccountOrPersona::sample(),
HierarchicalDeterministicFactorInstance::sample_mainnet_tx_account(
Hardened::from_local_key_space_unsecurified(0u32).unwrap(),
FactorSourceIDFromHash::sample_device(),
),
)
)
),
HDSignature::fake_sign_by_looking_up_mnemonic_amongst_samples(
HDSignatureInput::new(
TransactionIntentHash::sample(),
OwnedFactorInstance::new(
AddressOfAccountOrPersona::sample(),
HierarchicalDeterministicFactorInstance::sample_mainnet_tx_account(
Hardened::from_local_key_space_unsecurified(1u32).unwrap(),
FactorSourceIDFromHash::sample_device_other(),
),
)
)
)
])
);

assert_eq!(
result,
Err(CommonError::FactorOutcomeSignedFactorSourceIDMismatch)
);
}

#[test]
pub fn test_failure() {
let factor_source_id = FactorSourceIDFromHash::sample();

let sut = SUT::failure(factor_source_id);

assert_eq!(sut.as_neglected().unwrap().content, factor_source_id);
assert_eq!(
sut.as_neglected().unwrap().reason,
NeglectFactorReason::Failure
);
}

#[test]
pub fn test_skipped() {
let factor_source_id = FactorSourceIDFromHash::sample();

let sut = SUT::skipped(factor_source_id);

assert_eq!(sut.as_neglected().unwrap().content, factor_source_id);
assert_eq!(
sut.as_neglected().unwrap().reason,
NeglectFactorReason::UserExplicitlySkipped
);
}

#[test]
pub fn test_irrelevant() {
let factor_source_id = FactorSourceIDFromHash::sample();

let sut = SUT::irrelevant(factor_source_id);

assert_eq!(sut.as_neglected().unwrap().content, factor_source_id);
assert_eq!(
sut.as_neglected().unwrap().reason,
NeglectFactorReason::Irrelevant
);
}
}
6 changes: 4 additions & 2 deletions crates/app/signing-traits/src/host_interaction/mod.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
mod factor_outcome;
mod per_factor_source_input;
mod sign_interactor;
mod sign_request;
mod sign_response;
mod sign_with_factors_outcome;
mod transaction_sign_request_input;

pub use factor_outcome::*;
pub use per_factor_source_input::*;
pub use sign_interactor::*;
pub use sign_request::*;
pub use sign_response::*;
pub use sign_with_factors_outcome::*;
pub use transaction_sign_request_input::*;
Loading

0 comments on commit 7ac2d4a

Please sign in to comment.