+96
-12
crates/jacquard-repo/src/commit/mod.rs
+96
-12
crates/jacquard-repo/src/commit/mod.rs
···
12
12
use jacquard_common::types::crypto::PublicKey;
13
13
use jacquard_common::types::string::Did;
14
14
use jacquard_common::types::tid::Tid;
15
+
15
16
/// Repository commit object
16
17
///
17
18
/// This structure represents a signed commit in an AT Protocol repository.
···
43
44
pub sig: Bytes,
44
45
}
45
46
46
-
impl<'a> Commit<'a> {
47
+
/// Unsigned commit object.
48
+
/// Explicitly a separate struct minus the sig field to match deserialization/signatures
49
+
/// from other implementations.
50
+
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
51
+
pub struct UnsignedCommit<'a> {
52
+
/// Repository DID
53
+
#[serde(borrow)]
54
+
pub did: Did<'a>,
55
+
56
+
/// Commit version (2 or 3)
57
+
pub version: i64,
58
+
59
+
/// MST root CID
60
+
pub data: IpldCid,
61
+
62
+
/// Revision TID
63
+
pub rev: Tid,
64
+
65
+
/// Previous commit CID (None for initial commit)
66
+
pub prev: Option<IpldCid>,
67
+
}
68
+
69
+
impl<'a> UnsignedCommit<'a> {
47
70
/// Create new unsigned commit (version = 3, sig empty)
48
-
pub fn new_unsigned(did: Did<'a>, data: IpldCid, rev: Tid, prev: Option<IpldCid>) -> Self {
71
+
pub fn new_unsigned(
72
+
did: Did<'a>,
73
+
data: IpldCid,
74
+
rev: Tid,
75
+
prev: Option<IpldCid>,
76
+
) -> UnsignedCommit<'a> {
49
77
Self {
50
78
did,
51
79
version: 3,
52
80
data,
53
81
rev,
54
82
prev,
55
-
sig: Bytes::new(),
56
83
}
57
84
}
85
+
/// Get unsigned commit bytes (for signing/verification)
86
+
pub(super) fn unsigned_bytes(&self) -> Result<Vec<u8>> {
87
+
// Serialize without signature field
88
+
let unsigned = self.clone();
89
+
serde_ipld_dagcbor::to_vec(&unsigned)
90
+
.map_err(|e| crate::error::CommitError::Serialization(Box::new(e)).into())
91
+
}
58
92
59
93
/// Sign this commit with a key
60
-
pub fn sign(mut self, key: &impl SigningKey) -> Result<Self> {
94
+
pub fn sign(self, key: &impl SigningKey) -> Result<Commit<'a>> {
61
95
let unsigned = self.unsigned_bytes()?;
62
-
self.sig = key.sign_bytes(&unsigned)?;
63
-
Ok(self)
64
-
}
96
+
let sig = key.sign_bytes(&unsigned)?;
65
97
98
+
Ok(Commit {
99
+
did: self.did,
100
+
version: self.version,
101
+
data: self.data,
102
+
rev: self.rev,
103
+
prev: self.prev,
104
+
sig,
105
+
})
106
+
}
66
107
/// Get the repository DID
67
108
pub fn did(&self) -> &Did<'a> {
68
109
&self.did
···
82
123
pub fn prev(&self) -> Option<&IpldCid> {
83
124
self.prev.as_ref()
84
125
}
126
+
}
85
127
86
-
/// Get the signature bytes
87
-
pub fn sig(&self) -> &Bytes {
88
-
&self.sig
128
+
impl<'a> Commit<'a> {
129
+
/// Create new unsigned commit (version = 3, sig empty)
130
+
pub fn new_unsigned(
131
+
did: Did<'a>,
132
+
data: IpldCid,
133
+
rev: Tid,
134
+
prev: Option<IpldCid>,
135
+
) -> UnsignedCommit<'a> {
136
+
UnsignedCommit {
137
+
did,
138
+
version: 3,
139
+
data,
140
+
rev,
141
+
prev,
142
+
}
89
143
}
90
144
91
145
/// Get unsigned commit bytes (for signing/verification)
92
146
pub(super) fn unsigned_bytes(&self) -> Result<Vec<u8>> {
93
147
// Serialize without signature field
94
-
let mut unsigned = self.clone();
95
-
unsigned.sig = Bytes::new();
148
+
let unsigned = UnsignedCommit {
149
+
did: self.did.clone(),
150
+
version: self.version,
151
+
data: self.data.clone(),
152
+
rev: self.rev.clone(),
153
+
prev: self.prev.clone(),
154
+
};
96
155
serde_ipld_dagcbor::to_vec(&unsigned)
97
156
.map_err(|e| crate::error::CommitError::Serialization(Box::new(e)).into())
157
+
}
158
+
159
+
/// Get the repository DID
160
+
pub fn did(&self) -> &Did<'a> {
161
+
&self.did
162
+
}
163
+
164
+
/// Get the MST root CID
165
+
pub fn data(&self) -> &IpldCid {
166
+
&self.data
167
+
}
168
+
169
+
/// Get the revision TID
170
+
pub fn rev(&self) -> &Tid {
171
+
&self.rev
172
+
}
173
+
174
+
/// Get the previous commit CID
175
+
pub fn prev(&self) -> Option<&IpldCid> {
176
+
self.prev.as_ref()
177
+
}
178
+
179
+
/// Get the signature bytes
180
+
pub fn sig(&self) -> &Bytes {
181
+
&self.sig
98
182
}
99
183
100
184
/// Serialize to DAG-CBOR