Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Productionalization updates #50

Closed
wants to merge 45 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
fdbbaaf
new cargo project
piniom Jan 12, 2024
f85b6e3
first tests and build script
piniom Jan 15, 2024
b34f648
test gcd basic
piniom Jan 17, 2024
361e03b
extract verifying key converter
piniom Jan 22, 2024
eb5106f
verify signature tests
piniom Jan 23, 2024
4fe33e0
add a test
piniom Jan 23, 2024
5a20952
move types to mod.rs
piniom Jan 23, 2024
4528b0e
add ecdsa tests
piniom Jan 23, 2024
0cffae1
enable memory inspection
piniom Jan 24, 2024
c9ba75b
expand auth data
piniom Jan 24, 2024
c4a016c
extract test
piniom Jan 25, 2024
cb52146
cargo clippy
piniom Jan 25, 2024
b60452b
change local dependency to the git one
piniom Jan 25, 2024
0377dff
revert assertion removal
piniom Jan 29, 2024
ea105c6
split parser and extractor
piniom Jan 25, 2024
4fcaee7
refactor expand auth data
piniom Jan 25, 2024
db78b40
prelude
piniom Jan 25, 2024
d307cbd
add session folder
piniom Jan 25, 2024
a085f3d
signature proof tests
piniom Jan 25, 2024
da01cc0
signature deserialization
piniom Jan 25, 2024
9732dbf
rename new_ to new
piniom Jan 28, 2024
4df1a2c
session proptests
piniom Jan 31, 2024
4e2b396
move felt strategy to a separate file
piniom Jan 31, 2024
ef9e435
helpers prop test
piniom Jan 31, 2024
68b6d9e
verify ecdsa prop test
piniom Jan 31, 2024
e97befb
cargo fmt
piniom Jan 31, 2024
9694669
verify signature prop test
piniom Jan 31, 2024
9f5349e
expand auth data prop test
piniom Jan 31, 2024
cceaa59
remove python folder
piniom Jan 31, 2024
068a981
remove auth gen tests
piniom Jan 31, 2024
c5ab07c
remove session gen tests
piniom Jan 31, 2024
5da59af
update readme
piniom Jan 31, 2024
2fa4fa7
update args runner version
piniom Feb 27, 2024
d4ed08a
fix compile errors
piniom Feb 26, 2024
d9b1ec8
remove most warnings
piniom Feb 27, 2024
3052b97
fix the failing test by reverting the dependency update
piniom Feb 27, 2024
03144f4
remove more warnings
piniom Feb 27, 2024
0cd0fad
bump tool versions
piniom Feb 27, 2024
2f938f1
remove devnet runner test
piniom Feb 28, 2024
b7fd26b
bump merkle_tree version and update test
piniom Feb 28, 2024
a0789d4
change hashing to reflext alexandria fix
piniom Feb 28, 2024
6da9eaf
use a function from std lib when checking point bounds
piniom Feb 28, 2024
a22e7f6
cargo clippy
piniom Mar 11, 2024
92ab13d
Merge pull request #40 from cartridge-gg/feat/5/1/cairo25
tarrencev Mar 18, 2024
03d8cd7
Merge pull request #41 from cartridge-gg/feat/5/2/merkle
tarrencev Mar 18, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .tool-versions
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
scarb 2.4.3
starknet-foundry 0.14.0
scarb 2.5.4
starknet-foundry 0.18.0
python 3.9.18
dojo 0.4.4
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[workspace]
resolver = "2"
members = ["crates/account_sdk"]
members = ["crates/account_sdk", "crates/webauthn/tests"]

[workspace.package]
edition = "2021"
Expand Down Expand Up @@ -32,3 +32,4 @@ url = "2"
wasm-bindgen = "0.2"
webauthn-authenticator-rs = { version = "0.4" }
webauthn-rs-proto = "0.4"
account-sdk = { path = "crates/account_sdk" }
34 changes: 4 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ The project consists of several subfolders located in the ```crates``` directory

- **account_sdk** - a rust project to export and test functions for interacting with the custom account contract.
- **cartidge_account** - a cairo project with a custom account contract.
- **test_gen_scripts** - a python library to programatically generate cryptographic cairo tests.
- **webauthn** - cairo components to use in contracts.

The project has a global rust workspace.
Expand Down Expand Up @@ -45,39 +44,14 @@ cargo test

The scarb builds the contract and saves the compiled code in the `cartridge_account/target` folder. The tests then fetch (at compile time) the comipled code and deploy it to the local network. Note that obviously the contract needs to be recompiled for any changes to be applied in the compiled code.

## src
## webauthn

This is a cairo project with backend methods that will allow for various authentication methods in the custom contact.
Written based on [this specification](https://www.w3.org/TR/webauthn/).

### Running the tests

Some of the tests are auto-generated using python scripts.
See the `test_gen_scripts` for details.
The tests in `src/tests/` which end in `_gen_test.cairo` are auto-generated and might be changed by the python script. You can write your tests manually, but make sure the name of the test file doesn't end in `_gen_test.cairo`, and you place the import "`use ...;`" below the auto-generated imports in `src/tests.cairo`.

To run the tests:

```shell
scarb test
```

To again generate the tests:

```shell
python test_gen_scripts/main.py
```

## test_gen_scripts

This is a python library to programatically generate cryptographic cairo tests.

### Python Enviroment

Use pyenv to have specific version of python easily.
We use python3.9

```sh
pip install -r requirements.txt
python test_gen_scripts/main.py
You can run scarb test to run a few hand-written tests inside each ```auth``` and ```session``` crates. The bulk of the tests are located in the ```tests``` directory. These tests are written in rust and use property based testing provided by the [proptest](https://docs.rs/proptest/latest/proptest/) crate and use [cairo args runner](https://github.com/neotheprogramist/cairo-args-runner) to interface with and call cairo functions. To run these tests ```cd``` to the ```crates/webauthn/tests``` directory and run:
```bash
cargo test
```
12 changes: 6 additions & 6 deletions Scarb.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ edition = "2023_10"
version = "0.1.0"

[workspace.dependencies]
alexandria_data_structures = { git = "https://github.com/keep-starknet-strange/alexandria", rev = "085f17c87cf6d168032ef5840c39b8e18012284f" }
alexandria_encoding = { git = "https://github.com/keep-starknet-strange/alexandria", rev = "085f17c87cf6d168032ef5840c39b8e18012284f" }
alexandria_merkle_tree = { git = "https://github.com/keep-starknet-strange/alexandria", rev = "085f17c87cf6d168032ef5840c39b8e18012284f" }
openzeppelin = { git = "https://github.com/OpenZeppelin/cairo-contracts", tag = "v0.8.0" }
snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry", tag = "v0.14.0" }
starknet = "2.4.3"
alexandria_data_structures = { git = "https://github.com/keep-starknet-strange/alexandria", tag="cairo-v2.5.4" }
alexandria_encoding = { git = "https://github.com/keep-starknet-strange/alexandria", tag="cairo-v2.5.4" }
alexandria_merkle_tree = { git = "https://github.com/keep-starknet-strange/alexandria", tag="cairo-v2.5.4" }
openzeppelin = { git = "https://github.com/OpenZeppelin/cairo-contracts", tag = "v0.9.0" }
snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry", tag = "v0.18.0" }
starknet = "2.5.3"
webauthn_auth = { path = "crates/webauthn/auth" }
webauthn_session = { path = "crates/webauthn/session" }
2 changes: 1 addition & 1 deletion crates/account_sdk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ version.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[lib]
crate-type = ["cdylib"]
crate-type = ["lib"]

[dependencies]
anyhow.workspace = true
Expand Down
23 changes: 8 additions & 15 deletions crates/account_sdk/src/session_token/hash.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use starknet::{core::types::FieldElement, macros::felt};
use starknet_crypto::PoseidonHasher;
use starknet_crypto::{poseidon_hash, PoseidonHasher};

use crate::abigen::account::{Call, SessionSignature};

Expand All @@ -18,13 +18,6 @@ const POLICY_TYPE_HASH: FieldElement =

const STARKNET_MESSAGE_FELT: FieldElement = felt!("0x537461726b4e6574204d657373616765");

fn hash_two_elements(a: FieldElement, b: FieldElement) -> FieldElement {
let mut hasher = PoseidonHasher::new();
hasher.update(a);
hasher.update(b);
hasher.finalize()
}

pub fn compute_session_hash(
signature: SessionSignature,
chain_id: FieldElement,
Expand Down Expand Up @@ -89,9 +82,9 @@ pub fn compute_root(mut current_node: FieldElement, mut proof: Vec<FieldElement>
// We need to check if the current node is smaller than the current element of the proof.
// If it is, we need to swap the order of the hash.
current_node = if current_node < proof_element {
hash_two_elements(current_node, proof_element)
poseidon_hash(current_node, proof_element)
} else {
hash_two_elements(proof_element, current_node)
poseidon_hash(proof_element, current_node)
};
}
}
Expand Down Expand Up @@ -122,16 +115,16 @@ fn compute_proof(mut nodes: Vec<FieldElement>, index: usize, proof: &mut Vec<Fie
compute_proof(next_level, index_parent, proof)
}

fn get_next_level(nodes: &Vec<FieldElement>) -> Vec<FieldElement> {
fn get_next_level(nodes: &[FieldElement]) -> Vec<FieldElement> {
let mut next_level: Vec<FieldElement> = Vec::with_capacity(nodes.len() / 2);
for i in 0..nodes.len() / 2 {
let left = nodes[i * 2];
let right = nodes[i * 2 + 1];

let node = if left < right {
hash_two_elements(left, right)
poseidon_hash(left, right)
} else {
hash_two_elements(right, left)
poseidon_hash(right, left)
};
next_level.push(node);
}
Expand All @@ -142,11 +135,11 @@ fn get_next_level(nodes: &Vec<FieldElement>) -> Vec<FieldElement> {
#[test]
fn merkle_tree_poseidon_test() {
// [Setup] Merkle tree.
let root = felt!("0x7abc09d19c8a03abd4333a23f7823975c7bdd325170f0d32612b8baa1457d47");
let root = felt!("0x48924a3b2a7a7b7cc1c9371357e95e322899880a6534bdfe24e96a828b9d780");
let leaf = felt!("0x1");
let valid_proof = vec![
felt!("0x2"),
felt!("0x47ef3ad11ad3f8fc055281f1721acd537563ec134036bc4bd4de2af151f0832"),
felt!("0x338eb608d7e48306d01f5a8d4275dd85a52ba79aaf7a1a7b35808ba573c3669"),
];
let leaves = vec![felt!("0x1"), felt!("0x2"), felt!("0x3")];

Expand Down
8 changes: 3 additions & 5 deletions crates/account_sdk/src/session_token/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,11 +101,9 @@ impl Session {
.map(|c| self.call_proof(c).ok_or(SessionError::CallNotInPolicy))
.collect::<Result<Vec<_>, SessionError>>()?;

let proofs_flat = proofs.into_iter().fold(Ok(vec![]), |acc, proof| {
acc.and_then(|mut acc| {
acc.extend(proof.1.clone());
Ok(acc)
})
let proofs_flat = proofs.into_iter().try_fold(vec![], |mut acc, proof| {
acc.extend(proof.1.clone());
Ok(acc)
})?;

assert!(!self.session_token().is_empty(), "Session token is empty");
Expand Down
7 changes: 1 addition & 6 deletions crates/account_sdk/src/tests/runners_test.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
use super::runners::{devnet_runner::DevnetRunner, katana_runner::KatanaRunner, TestnetRunner};
use super::runners::{katana_runner::KatanaRunner, TestnetRunner};

#[test]
fn test_katana_runner() {
KatanaRunner::load();
}

#[test]
fn test_devnet_runner() {
DevnetRunner::load();
}
32 changes: 22 additions & 10 deletions crates/account_sdk/src/webauthn_signer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,7 @@ impl P256r1Signer {
Self { signing_key, rp_id }
}
pub fn public_key_bytes(&self) -> ([u8; 32], [u8; 32]) {
let verifying_key: VerifyingKey = VerifyingKey::from(&self.signing_key);
let encoded = &verifying_key.to_encoded_point(false);
let (x, y) = match encoded.coordinates() {
Coordinates::Uncompressed { x, y } => (x, y),
_ => panic!("unexpected compression"),
};
(
x.as_slice().try_into().unwrap(),
y.as_slice().try_into().unwrap(),
)
P256VerifyingKeyConverter::new(*self.signing_key.verifying_key()).to_bytes()
}
pub fn sign(&self, challenge: &[u8]) -> AuthenticatorAssertionResponse {
use sha2::{digest::Update, Digest, Sha256};
Expand All @@ -70,6 +61,27 @@ impl P256r1Signer {
}
}

pub struct P256VerifyingKeyConverter {
pub verifying_key: VerifyingKey,
}

impl P256VerifyingKeyConverter {
pub fn new(verifying_key: VerifyingKey) -> Self {
Self { verifying_key }
}
pub fn to_bytes(&self) -> ([u8; 32], [u8; 32]) {
let encoded = &self.verifying_key.to_encoded_point(false);
let (x, y) = match encoded.coordinates() {
Coordinates::Uncompressed { x, y } => (x, y),
_ => panic!("unexpected compression"),
};
(
x.as_slice().try_into().unwrap(),
y.as_slice().try_into().unwrap(),
)
}
}

#[test]
fn test_signer() {
let rp_id = "https://localhost:8080".to_string();
Expand Down
2 changes: 1 addition & 1 deletion crates/cartridge_account/src/erc20.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ mod ERC20 {
}

#[generate_trait]
#[external(v0)]
#[abi(per_item)]
impl ExternalImpl of ExternalTrait {
fn burn(ref self: ContractState, value: u256) {
let caller = get_caller_address();
Expand Down
9 changes: 5 additions & 4 deletions crates/cartridge_account/src/lib.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,8 @@ mod Account {
// External
//

#[external(v0)]
// TODO: Remove this warning
#[abi(embed_v0)]
impl SRC6Impl of interface::ISRC6<ContractState> {
fn __execute__(self: @ContractState, mut calls: Array<Call>) -> Array<Span<felt252>> {
// Avoid calls from other contracts
Expand Down Expand Up @@ -126,14 +127,14 @@ mod Account {
}
}

#[external(v0)]
#[abi(embed_v0)]
impl DeclarerImpl of interface::IDeclarer<ContractState> {
fn __validate_declare__(self: @ContractState, class_hash: felt252) -> felt252 {
self.validate_ecdsa_transaction()
}
}

#[external(v0)]
#[abi(embed_v0)]
impl PublicKeyImpl of super::IPublicKey<ContractState> {
fn get_public_key(self: @ContractState) -> felt252 {
self.Account_public_key.read()
Expand Down Expand Up @@ -240,6 +241,6 @@ mod Account {

fn _execute_single_call(call: Call) -> Span<felt252> {
let Call{to, selector, calldata } = call;
starknet::call_contract_syscall(to, selector, calldata.span()).unwrap()
starknet::call_contract_syscall(to, selector, calldata).unwrap()
}
}
4 changes: 2 additions & 2 deletions crates/cartridge_account/tests/test_account.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ impl TransferCallImpl of TransferCallTrait {
let mut calldata = array![];
calldata.append_serde(self.recipient);
calldata.append_serde(self.amount);
Call { to: self.erc20, selector: selectors::transfer, calldata: calldata }
Call { to: self.erc20, selector: selectors::transfer, calldata: calldata.span() }
}
}

Expand Down Expand Up @@ -121,7 +121,7 @@ fn test_account() {

let recipient = contract_address_const::<0x123>();
let call = TransferCall { erc20: erc20_address, recipient: recipient, amount: 200 }.to_call();
let ret = account.__execute__(array![call]);
let _ret = account.__execute__(array![call]);

// Verify that the transfer of tokens was succesful
assert(erc20.balance_of(account_address) == 800, 'Should have remained');
Expand Down
71 changes: 0 additions & 71 deletions crates/test_gen_scripts/auth/expand_auth_data_test.py

This file was deleted.

Loading
Loading