Skip to content

Commit fd85fd1

Browse files
committed
feat: start impl hashchain verification
1 parent e8e7417 commit fd85fd1

File tree

10 files changed

+265
-67
lines changed

10 files changed

+265
-67
lines changed

Cargo.lock

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

Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ arecibo = { git = "https://github.com/deltadevsde/arecibo" }
7575
sha2 = "0.10.8"
7676
auto_impl = "1.2.0"
7777
bincode = "1.3.3"
78+
ed25519-consensus = "2.1.0"
79+
curve25519-dalek = "4.1.3"
80+
secp256k1 = "0.29.0"
7881
sp1-zkvm = { version = "1.2.0" }
7982
sp1-sdk = { version = "1.2.0" }
8083
prism-common = { path = "crates/common" }
@@ -85,6 +88,9 @@ prism-groth16 = { path = "crates/groth16" }
8588

8689
[patch.crates-io]
8790
sha2-v0-10-8 = { git = "https://github.com/sp1-patches/RustCrypto-hashes", package = "sha2", branch = "patch-sha2-v0.10.8" }
91+
curve25519-dalek = { git = "https://github.com/sp1-patches/curve25519-dalek", branch = "patch-curve25519-v4.1.3" }
92+
secp256k1 = { git = "https://github.com/sp1-patches/rust-secp256k1", branch = "patch-secp256k1-v0.29.0" }
93+
ed25519-consensus = { git = "https://github.com/sp1-patches/ed25519-consensus", branch = "patch-v2.1.0" }
8894

8995
# [workspace.dev-dependencies]
9096
# serial_test = "3.1.1"

crates/common/src/hashchain.rs

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ use serde::{Deserialize, Serialize};
44
use std::ops::{Deref, DerefMut};
55

66
use crate::{
7-
operation::{AccountSource, Operation},
7+
operation::{
8+
AccountSource, CreateAccountArgs, KeyOperationArgs, Operation, PublicKey,
9+
ServiceChallengeInput, SignatureBundle,
10+
},
811
tree::{hash, Digest, Hasher},
912
};
1013

@@ -71,12 +74,18 @@ impl Hashchain {
7174
self.entries.iter_mut()
7275
}
7376

74-
pub fn create_account(&mut self, value: String, source: AccountSource) -> Result<Digest> {
75-
let operation = Operation::CreateAccount {
77+
pub fn create_account(
78+
&mut self,
79+
value: String,
80+
service_id: String,
81+
challenge: ServiceChallengeInput,
82+
) -> Result<Digest> {
83+
let operation = Operation::CreateAccount(CreateAccountArgs {
7684
id: self.id.clone(),
7785
value,
78-
source,
79-
};
86+
service_id,
87+
challenge,
88+
});
8089
self.push(operation)
8190
}
8291

@@ -101,19 +110,21 @@ impl Hashchain {
101110
}
102111

103112
// TODO: Obviously, this needs to be authenticated by an existing key.
104-
pub fn add(&mut self, value: String) -> Result<Digest> {
105-
let operation = Operation::Add {
113+
pub fn add(&mut self, value: PublicKey, signature: SignatureBundle) -> Result<Digest> {
114+
let operation = Operation::AddKey(KeyOperationArgs {
106115
id: self.id.clone(),
107116
value,
108-
};
117+
signature,
118+
});
109119
self.push(operation)
110120
}
111121

112-
pub fn revoke(&mut self, value: String) -> Result<Digest> {
113-
let operation = Operation::Revoke {
122+
pub fn revoke(&mut self, value: PublicKey, signature: SignatureBundle) -> Result<Digest> {
123+
let operation = Operation::RevokeKey(KeyOperationArgs {
114124
id: self.id.clone(),
115125
value,
116-
};
126+
signature,
127+
});
117128
self.push(operation)
118129
}
119130

crates/common/src/operation.rs

Lines changed: 66 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,65 @@ use celestia_types::Blob;
33
use serde::{Deserialize, Serialize};
44
use std::fmt::Display;
55

6+
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
7+
/// Represents a public key supported by the system.
8+
pub enum PublicKey {
9+
Secp256k1(Vec<u8>), // Bitcoin, Ethereum
10+
Ed25519(Vec<u8>), // Cosmos, OpenSSH, GnuPG
11+
Curve25519(Vec<u8>), // Signal, Tor
12+
}
13+
14+
impl PublicKey {
15+
pub fn as_bytes(&self) -> &[u8] {
16+
match self {
17+
PublicKey::Secp256k1(bytes) => bytes,
18+
PublicKey::Ed25519(bytes) => bytes,
19+
PublicKey::Curve25519(bytes) => bytes,
20+
}
21+
}
22+
}
23+
24+
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
25+
/// Represents a signature bundle, which includes the index of the key
26+
/// in the user's hashchain and the associated signature.
27+
pub struct SignatureBundle {
28+
pub key_idx: u64, // Index of the key in the hashchain
29+
pub signature: Vec<u8>, // The actual signature
30+
}
31+
32+
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
33+
/// Input required to complete a challenge for account creation.
34+
pub enum ServiceChallengeInput {
35+
Signed(Vec<u8>), // Signature bytes
36+
}
37+
638
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
739
// An [`Operation`] represents a state transition in the system.
840
// In a blockchain analogy, this would be the full set of our transaction types.
941
pub enum Operation {
1042
// Creates a new account with the given id and value.
11-
CreateAccount {
12-
id: String,
13-
value: String,
14-
source: AccountSource,
15-
},
43+
CreateAccount(CreateAccountArgs),
1644
// Adds a value to an existing account.
17-
Add {
18-
id: String,
19-
value: String,
20-
},
45+
AddKey(KeyOperationArgs),
2146
// Revokes a value from an existing account.
22-
Revoke {
23-
id: String,
24-
value: String,
25-
},
47+
RevokeKey(KeyOperationArgs),
48+
}
49+
50+
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
51+
/// Arguments for creating an account with a service.
52+
pub struct CreateAccountArgs {
53+
pub id: String, // Account ID
54+
pub value: String, // Initial value
55+
pub service_id: String, // Associated service ID
56+
pub challenge: ServiceChallengeInput, // Challenge input for verification
57+
}
58+
59+
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
60+
/// Common structure for operations involving keys (adding or revoking).
61+
pub struct KeyOperationArgs {
62+
pub id: String, // Account ID
63+
pub value: PublicKey, // Public key being added or revoked
64+
pub signature: SignatureBundle, // Signature to authorize the action
2665
}
2766

2867
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
@@ -34,17 +73,24 @@ pub enum AccountSource {
3473
impl Operation {
3574
pub fn id(&self) -> String {
3675
match self {
37-
Operation::CreateAccount { id, .. } => id.clone(),
38-
Operation::Add { id, .. } => id.clone(),
39-
Operation::Revoke { id, .. } => id.clone(),
76+
Operation::CreateAccount(args) => args.id.clone(),
77+
Operation::AddKey(args) => args.id.clone(),
78+
Operation::RevokeKey(args) => args.id.clone(),
79+
}
80+
}
81+
82+
pub fn string_value(&self) -> Option<String> {
83+
match self {
84+
Operation::CreateAccount(args) => Some(args.value.clone()),
85+
_ => None,
4086
}
4187
}
4288

43-
pub fn value(&self) -> String {
89+
pub fn public_key_value(&self) -> Option<PublicKey> {
4490
match self {
45-
Operation::CreateAccount { value, .. } => value.clone(),
46-
Operation::Add { value, .. } => value.clone(),
47-
Operation::Revoke { value, .. } => value.clone(),
91+
Operation::AddKey(args) => Some(args.value.clone()),
92+
Operation::RevokeKey(args) => Some(args.value.clone()),
93+
_ => None,
4894
}
4995
}
5096
}

crates/groth16/src/hashchain.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use anyhow::Result;
1+
use anyhow::{anyhow, Result};
22
use bellman::{Circuit, ConstraintSystem, SynthesisError};
33
use bls12_381::Scalar;
44
use indexed_merkle_tree::sha256_mod;
@@ -19,7 +19,12 @@ impl HashChainEntryCircuit {
1919
let parsed_value = hashed_value.try_into()?;
2020
let mut parsed_hashchain: Vec<Scalar> = vec![];
2121
for entry in hashchain {
22-
let hashed_entry_value = sha256_mod(entry.operation.value().as_bytes());
22+
let public_key_value = entry
23+
.operation
24+
.public_key_value()
25+
.ok_or_else(|| anyhow!("Missing public key value in hashchain entry"))?;
26+
27+
let hashed_entry_value = sha256_mod(public_key_value.as_bytes());
2328
parsed_hashchain.push(hashed_entry_value.try_into()?)
2429
}
2530
Ok(HashChainEntryCircuit {

crates/prism/src/node_types/sequencer.rs

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ use async_trait::async_trait;
33
use ed25519::Signature;
44
use ed25519_dalek::{Signer, SigningKey};
55
use jmt::KeyHash;
6-
use prism_common::tree::{hash, Batch, Digest, Hasher, KeyDirectoryTree, Proof, SnarkableTree};
6+
use prism_common::{
7+
operation::{CreateAccountArgs, KeyOperationArgs},
8+
tree::{hash, Batch, Digest, Hasher, KeyDirectoryTree, Proof, SnarkableTree},
9+
};
710
use std::{self, str::FromStr, sync::Arc};
811
use tokio::{
912
sync::{
@@ -383,7 +386,16 @@ impl Sequencer {
383386
/// Updates the state from an already verified pending operation.
384387
async fn process_operation(&self, operation: &Operation) -> Result<Proof> {
385388
match operation {
386-
Operation::Add { id, .. } | Operation::Revoke { id, .. } => {
389+
Operation::AddKey(KeyOperationArgs {
390+
id,
391+
value,
392+
signature,
393+
})
394+
| Operation::RevokeKey(KeyOperationArgs {
395+
id,
396+
value,
397+
signature,
398+
}) => {
387399
// verify that the hashchain already exists
388400
let mut current_chain = self
389401
.db
@@ -410,9 +422,14 @@ impl Sequencer {
410422

411423
Ok(Proof::Update(proof))
412424
}
413-
Operation::CreateAccount { id, value, source } => {
425+
Operation::CreateAccount(CreateAccountArgs {
426+
id,
427+
value,
428+
service_id,
429+
challenge,
430+
}) => {
414431
// validation of account source
415-
match source {
432+
match challenge {
416433
// TODO: use Signature, not String
417434
AccountSource::SignedBySequencer { signature } => {
418435
let sig = Signature::from_str(signature)

0 commit comments

Comments
 (0)