Skip to content

Commit bc21d9d

Browse files
sequencer tests
1 parent 9d23d1c commit bc21d9d

File tree

11 files changed

+421
-375
lines changed

11 files changed

+421
-375
lines changed

Cargo.lock

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/common/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ homepage.workspace = true
77
repository.workspace = true
88

99
[dependencies]
10+
prism-errors.workspace = true
1011
anyhow.workspace = true
1112
bls12_381.workspace = true
1213
borsh.workspace = true
@@ -17,4 +18,6 @@ sha2.workspace = true
1718
celestia-types.workspace = true
1819
bincode.workspace = true
1920
ed25519-dalek.workspace = true
21+
ed25519.workspace = true
22+
base64.workspace = true
2023
rand.workspace = true

crates/common/src/hashchain.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,11 +130,13 @@ impl Hashchain {
130130
pub fn create_account(
131131
&mut self,
132132
value: PublicKey,
133+
signature: Vec<u8>,
133134
service_id: String,
134135
challenge: ServiceChallengeInput,
135136
) -> Result<Digest> {
136137
let operation = Operation::CreateAccount(CreateAccountArgs {
137138
id: self.id.clone(),
139+
signature,
138140
value,
139141
service_id,
140142
challenge,

crates/common/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
pub mod hashchain;
22
pub mod operation;
3+
pub mod signed_content;
34
pub mod tree;
45

56
// todo: add testing feature for use across crates, so we dont have to expose it

crates/common/src/operation.rs

Lines changed: 70 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,24 @@
11
use anyhow::{Context, Result};
2+
use bincode;
23
use celestia_types::Blob;
4+
use prism_errors::GeneralError;
35
use serde::{Deserialize, Serialize};
4-
use std::fmt::Display;
6+
use std::{self, fmt::Display, str::FromStr};
57

68
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq, Hash)]
79
/// Represents a public key supported by the system.
810
pub enum PublicKey {
9-
Secp256k1(Vec<u8>), // Bitcoin, Ethereum
10-
Ed25519(Vec<u8>), // Cosmos, OpenSSH, GnuPG
11-
Curve25519(Vec<u8>), // Signal, Tor
11+
// Secp256k1(Vec<u8>), // Bitcoin, Ethereum
12+
Ed25519(Vec<u8>), // Cosmos, OpenSSH, GnuPG
13+
// Curve25519(Vec<u8>), // Signal, Tor
1214
}
1315

1416
impl PublicKey {
1517
pub fn as_bytes(&self) -> &[u8] {
1618
match self {
17-
PublicKey::Secp256k1(bytes) => bytes,
19+
// PublicKey::Secp256k1(bytes) => bytes,
1820
PublicKey::Ed25519(bytes) => bytes,
19-
PublicKey::Curve25519(bytes) => bytes,
21+
// PublicKey::Curve25519(bytes) => bytes,
2022
}
2123
}
2224
}
@@ -50,8 +52,9 @@ pub enum Operation {
5052
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
5153
/// Arguments for creating an account with a service.
5254
pub struct CreateAccountArgs {
53-
pub id: String, // Account ID
54-
pub value: PublicKey, // Public Key
55+
pub id: String, // Account ID
56+
pub value: PublicKey, // Public Key
57+
pub signature: Vec<u8>,
5558
pub service_id: String, // Associated service ID
5659
pub challenge: ServiceChallengeInput, // Challenge input for verification
5760
}
@@ -80,6 +83,65 @@ impl Operation {
8083
Operation::CreateAccount(args) => Some(args.value.clone()),
8184
}
8285
}
86+
87+
pub fn validate(&self) -> Result<()> {
88+
match &self {
89+
Operation::AddKey(KeyOperationArgs {
90+
id,
91+
value,
92+
signature,
93+
})
94+
| Operation::RevokeKey(KeyOperationArgs {
95+
id,
96+
value,
97+
signature,
98+
}) => {
99+
if id.is_empty() {
100+
return Err(
101+
GeneralError::MissingArgumentError("id is empty".to_string()).into(),
102+
);
103+
}
104+
105+
if signature.signature.is_empty() {
106+
return Err(GeneralError::MissingArgumentError(
107+
"signature is empty".to_string(),
108+
)
109+
.into());
110+
}
111+
112+
// verify_signature(self, None).context("Failed to verify signature")?;
113+
114+
Ok(())
115+
}
116+
Operation::CreateAccount(CreateAccountArgs {
117+
id,
118+
value,
119+
signature,
120+
service_id: _,
121+
challenge,
122+
}) => {
123+
if id.is_empty() {
124+
return Err(
125+
GeneralError::MissingArgumentError("id is empty".to_string()).into(),
126+
);
127+
}
128+
129+
match challenge {
130+
ServiceChallengeInput::Signed(signature) => {
131+
if signature.is_empty() {
132+
return Err(GeneralError::MissingArgumentError(
133+
"challenge data is empty".to_string(),
134+
)
135+
.into());
136+
}
137+
// verify_signature(self, None).context("Failed to verify signature")?;
138+
}
139+
}
140+
141+
Ok(())
142+
}
143+
}
144+
}
83145
}
84146

85147
impl Display for Operation {
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
use anyhow::Result;
2+
use base64::{engine::general_purpose::STANDARD as engine, Engine as _};
3+
use ed25519::Signature;
4+
use ed25519_dalek::{Verifier, VerifyingKey as Ed25519VerifyingKey};
5+
use prism_errors::{GeneralError, PrismError};
6+
7+
pub trait SignedContent {
8+
fn get_signature(&self) -> Result<Signature>;
9+
fn get_plaintext(&self) -> Result<Vec<u8>>;
10+
fn get_public_key(&self) -> Result<String>;
11+
}
12+
13+
pub fn decode_public_key(pub_key_str: &String) -> Result<Ed25519VerifyingKey> {
14+
// decode the public key from base64 string to bytes
15+
let public_key_bytes = engine
16+
.decode(pub_key_str)
17+
.map_err(|e| GeneralError::DecodingError(format!("base64 string: {}", e)))?;
18+
19+
let public_key_array: [u8; 32] = public_key_bytes
20+
.try_into()
21+
.map_err(|_| GeneralError::ParsingError("Vec<u8> to [u8; 32]".to_string()))?;
22+
23+
Ed25519VerifyingKey::from_bytes(&public_key_array)
24+
.map_err(|_| GeneralError::DecodingError("ed25519 verifying key".to_string()).into())
25+
}
26+
27+
// verifies the signature of a given signable item and returns the content of the item if the signature is valid
28+
pub fn verify_signature<T: SignedContent>(
29+
item: &T,
30+
optional_public_key: Option<String>,
31+
) -> Result<Vec<u8>> {
32+
let public_key_str = match optional_public_key {
33+
Some(key) => key,
34+
None => item.get_public_key()?,
35+
};
36+
37+
let public_key = decode_public_key(&public_key_str)
38+
.map_err(|_| PrismError::General(GeneralError::InvalidPublicKey))?;
39+
40+
let content = item.get_plaintext()?;
41+
let signature = item.get_signature()?;
42+
43+
match public_key.verify(content.as_slice(), &signature) {
44+
Ok(_) => Ok(content),
45+
Err(e) => Err(GeneralError::InvalidSignature(e).into()),
46+
}
47+
}

crates/common/src/test_utils.rs

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
use crate::hashchain::{Hashchain, HashchainEntry};
2-
use crate::operation::{KeyOperationArgs, Operation, PublicKey, SignatureBundle};
3-
use crate::tree::{hash, InsertProof, KeyDirectoryTree, SnarkableTree, UpdateProof};
1+
use crate::{
2+
hashchain::{Hashchain, HashchainEntry},
3+
operation::{KeyOperationArgs, Operation, PublicKey, SignatureBundle},
4+
tree::{hash, InsertProof, KeyDirectoryTree, SnarkableTree, UpdateProof},
5+
};
46
use anyhow::{anyhow, Result};
57
use ed25519_dalek::{Signer, SigningKey};
68
use jmt::{mock::MockTreeStore, KeyHash};
79
use rand::{rngs::StdRng, Rng};
8-
use std::collections::HashSet;
9-
use std::sync::Arc;
10+
use std::{collections::HashSet, sync::Arc};
1011

1112
pub struct TestTreeState {
1213
pub tree: KeyDirectoryTree<MockTreeStore>,
@@ -152,12 +153,3 @@ pub fn create_add_key_operation_with_test_value(id: &str, signing_key: &SigningK
152153
signature: create_mock_signature(signing_key, id.as_bytes()),
153154
})
154155
}
155-
156-
pub fn random_create_account(id: &str) -> Operation::CreateAccount {
157-
let signing_key = create_mock_signing_key();
158-
Operation::CreateAccount(CreateAccountArgs {
159-
id: id.to_string(),
160-
value: PublicKey::Ed25519(signing_key.verifying_key().to_bytes().to_vec()),
161-
signature: create_mock_signature(signing_key, id.as_bytes()),
162-
})
163-
}

0 commit comments

Comments
 (0)