pub fn seal_chain(
turns: &[Value],
sign: Option<&SignOpts>,
) -> Result<Vec<Value>, Error>Examples found in repository?
examples/quickstart.rs (line 35)
8fn main() {
9 // 1. Generate an Ed25519 keypair.
10 let sk = SigningKey::generate(&mut OsRng);
11 let sign = SignOpts {
12 privkey: sk.to_bytes(),
13 pubkey: sk.verifying_key().to_bytes(),
14 };
15
16 // 2. Build three plain turns. timestamp_ns differs so each turn hashes uniquely.
17 let mk = |turn: u64, role: &str, content: &str, ts_offset: u64| {
18 json!({
19 "version": "scroll/0.1",
20 "turn": turn,
21 "role": role,
22 "model": { "vendor": "anthropic", "id": "claude-opus-4-7" },
23 "params": { "temperature": 0, "top_p": 1 },
24 "messages": [{ "role": role, "content": content }],
25 "timestamp_ns": 1_700_000_000_000_000_000u64 + ts_offset,
26 })
27 };
28 let turns: Vec<Value> = vec![
29 mk(0, "user", "What is the capital of France?", 0),
30 mk(1, "assistant", "Paris.", 1),
31 mk(2, "user", "Thanks!", 2),
32 ];
33
34 // 3. Seal + sign as a chain. seal_chain links each turn via prev_hash.
35 let chain = seal_chain(&turns, Some(&sign)).expect("seal_chain");
36 println!("sealed {} turns, all hashes set", chain.len());
37
38 // 4. Verify the clean chain.
39 let clean = verify(&chain, Some(&sign.pubkey));
40 println!("verify clean: ok={}", clean.ok);
41
42 // 5. Tamper: replace one hex char in turn[1]'s hash.
43 let mut tampered = chain.clone();
44 let h = tampered[1]["hash"].as_str().unwrap().to_string();
45 let last = h.chars().last().unwrap();
46 let new_last = if last == '0' { 'f' } else { '0' };
47 let mut new_h: String = h[..h.len() - 1].to_string();
48 new_h.push(new_last);
49 tampered[1]["hash"] = json!(new_h);
50
51 let bad = verify(&tampered, Some(&sign.pubkey));
52 let reason = bad.failures.first().map(|f| f.reason).unwrap_or("none");
53 println!("verify tampered: ok={} reason={}", bad.ok, reason);
54}