Skip to content

Commit 33b90bc

Browse files
CopilotSteake
andcommitted
Add comprehensive VRF integration tests
Co-authored-by: Steake <530040+Steake@users.noreply.github.com>
1 parent 3344eb4 commit 33b90bc

1 file changed

Lines changed: 353 additions & 0 deletions

File tree

tests/vrf_integration.rs

Lines changed: 353 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,353 @@
1+
//! Integration tests for VRF (Verifiable Random Function) implementation
2+
//!
3+
//! These tests verify the complete VRF integration across the BitCell codebase,
4+
//! including key derivation, proof generation/verification, and blockchain integration.
5+
6+
use bitcell_crypto::{PublicKey, SecretKey, Hash256};
7+
use bitcell_node::blockchain::Blockchain;
8+
use bitcell_metrics::MetricsRegistry;
9+
use std::sync::Arc;
10+
11+
/// Test that VRF keys are correctly derived from secp256k1 keys
12+
#[test]
13+
fn test_vrf_key_derivation_deterministic() {
14+
// Same secp256k1 key should always produce same VRF outputs
15+
let seed = [42u8; 32];
16+
let sk1 = SecretKey::from_bytes(&seed).unwrap();
17+
let sk2 = SecretKey::from_bytes(&seed).unwrap();
18+
19+
let message = b"test_message_for_vrf";
20+
21+
let (output1, _proof1) = sk1.vrf_prove(message);
22+
let (output2, _proof2) = sk2.vrf_prove(message);
23+
24+
assert_eq!(output1, output2, "VRF outputs should be deterministic for same key");
25+
}
26+
27+
/// Test that different secp256k1 keys produce different VRF outputs
28+
#[test]
29+
fn test_vrf_key_derivation_unique() {
30+
let sk1 = SecretKey::generate();
31+
let sk2 = SecretKey::generate();
32+
33+
let message = b"same_message";
34+
35+
let (output1, _) = sk1.vrf_prove(message);
36+
let (output2, _) = sk2.vrf_prove(message);
37+
38+
assert_ne!(output1, output2, "Different keys should produce different VRF outputs");
39+
}
40+
41+
/// Test VRF proof generation and verification with valid proofs
42+
#[test]
43+
fn test_vrf_proof_verification_valid() {
44+
let sk = SecretKey::generate();
45+
let pk = sk.public_key();
46+
47+
let message = b"block_hash_test";
48+
let (output, proof) = sk.vrf_prove(message);
49+
50+
// Verify the proof
51+
let verified_output = proof.verify(&pk, message)
52+
.expect("Valid proof should verify successfully");
53+
54+
assert_eq!(output, verified_output, "Verified output should match original output");
55+
}
56+
57+
/// Test that VRF proofs verify correctly for different messages
58+
#[test]
59+
fn test_vrf_proof_different_messages() {
60+
let sk = SecretKey::generate();
61+
let pk = sk.public_key();
62+
63+
let messages = [
64+
b"message_1".as_slice(),
65+
b"message_2".as_slice(),
66+
b"message_3".as_slice(),
67+
b"a_very_long_message_that_tests_vrf_with_more_data".as_slice(),
68+
&[0u8; 100], // Binary data
69+
];
70+
71+
for message in &messages {
72+
let (output, proof) = sk.vrf_prove(message);
73+
let verified = proof.verify(&pk, message)
74+
.expect("Proof should verify for valid message");
75+
assert_eq!(output, verified);
76+
}
77+
}
78+
79+
/// Test VRF proof with wrong message fails verification
80+
#[test]
81+
fn test_vrf_proof_wrong_message() {
82+
let sk = SecretKey::generate();
83+
let pk = sk.public_key();
84+
85+
let correct_message = b"correct_message";
86+
let wrong_message = b"wrong_message";
87+
88+
let (_output, proof) = sk.vrf_prove(correct_message);
89+
90+
// Verification with wrong message should still work (VRF verifies proof structure),
91+
// but will produce different output
92+
let verified1 = proof.verify(&pk, correct_message)
93+
.expect("Should verify with correct message");
94+
let verified2 = proof.verify(&pk, wrong_message)
95+
.expect("VRF proof structure should still be valid");
96+
97+
// The outputs will differ because the message is part of the VRF input
98+
assert_ne!(verified1, verified2, "Different messages should produce different verified outputs");
99+
}
100+
101+
/// Test VRF chaining in blockchain - each block uses previous VRF output
102+
#[test]
103+
fn test_vrf_chaining_in_blockchain() {
104+
let sk = Arc::new(SecretKey::generate());
105+
let metrics = MetricsRegistry::new();
106+
let blockchain = Blockchain::new(sk.clone(), metrics);
107+
108+
// Produce and add 5 blocks
109+
let mut blocks = Vec::new();
110+
for i in 0..5 {
111+
let block = blockchain.produce_block(
112+
vec![],
113+
vec![],
114+
sk.public_key(),
115+
).expect(&format!("Should produce block {}", i + 1));
116+
117+
// Verify VRF output is non-zero
118+
assert_ne!(block.header.vrf_output, [0u8; 32],
119+
"Block {} VRF output should be non-zero", i + 1);
120+
121+
// Verify VRF proof exists
122+
assert!(!block.header.vrf_proof.is_empty(),
123+
"Block {} should have VRF proof", i + 1);
124+
125+
// If not first block, verify VRF output differs from previous
126+
if i > 0 {
127+
assert_ne!(block.header.vrf_output, blocks[i - 1].header.vrf_output,
128+
"Block {} VRF should differ from block {} due to chaining", i + 1, i);
129+
}
130+
131+
// Validate and add block
132+
blockchain.validate_block(&block)
133+
.expect(&format!("Block {} should be valid", i + 1));
134+
blockchain.add_block(block.clone())
135+
.expect(&format!("Should add block {}", i + 1));
136+
137+
blocks.push(block);
138+
}
139+
140+
// Verify all VRF outputs are unique
141+
for i in 0..blocks.len() {
142+
for j in (i + 1)..blocks.len() {
143+
assert_ne!(blocks[i].header.vrf_output, blocks[j].header.vrf_output,
144+
"Block {} and block {} should have different VRF outputs", i + 1, j + 1);
145+
}
146+
}
147+
}
148+
149+
/// Test VRF determinism - recreating the same chain produces same VRF sequence
150+
#[test]
151+
fn test_vrf_blockchain_determinism() {
152+
let sk = Arc::new(SecretKey::generate());
153+
154+
// Create first blockchain and produce 3 blocks
155+
let metrics1 = MetricsRegistry::new();
156+
let blockchain1 = Blockchain::new(sk.clone(), metrics1);
157+
158+
let block1_v1 = blockchain1.produce_block(vec![], vec![], sk.public_key()).unwrap();
159+
blockchain1.add_block(block1_v1.clone()).unwrap();
160+
161+
let block2_v1 = blockchain1.produce_block(vec![], vec![], sk.public_key()).unwrap();
162+
blockchain1.add_block(block2_v1.clone()).unwrap();
163+
164+
let block3_v1 = blockchain1.produce_block(vec![], vec![], sk.public_key()).unwrap();
165+
166+
// Create second blockchain with same key
167+
let metrics2 = MetricsRegistry::new();
168+
let blockchain2 = Blockchain::new(sk.clone(), metrics2);
169+
170+
let block1_v2 = blockchain2.produce_block(vec![], vec![], sk.public_key()).unwrap();
171+
blockchain2.add_block(block1_v2.clone()).unwrap();
172+
173+
let block2_v2 = blockchain2.produce_block(vec![], vec![], sk.public_key()).unwrap();
174+
blockchain2.add_block(block2_v2.clone()).unwrap();
175+
176+
let block3_v2 = blockchain2.produce_block(vec![], vec![], sk.public_key()).unwrap();
177+
178+
// Verify same VRF sequence
179+
assert_eq!(block1_v1.header.vrf_output, block1_v2.header.vrf_output,
180+
"First block VRF should be deterministic");
181+
assert_eq!(block2_v1.header.vrf_output, block2_v2.header.vrf_output,
182+
"Second block VRF should be deterministic");
183+
assert_eq!(block3_v1.header.vrf_output, block3_v2.header.vrf_output,
184+
"Third block VRF should be deterministic");
185+
}
186+
187+
/// Test VRF with multiple different validators
188+
#[test]
189+
fn test_vrf_multiple_validators() {
190+
let validators = vec![
191+
Arc::new(SecretKey::generate()),
192+
Arc::new(SecretKey::generate()),
193+
Arc::new(SecretKey::generate()),
194+
];
195+
196+
let metrics = MetricsRegistry::new();
197+
let blockchain = Blockchain::new(validators[0].clone(), metrics);
198+
199+
// Each validator produces a block
200+
for (i, validator) in validators.iter().enumerate() {
201+
let block = blockchain.produce_block(
202+
vec![],
203+
vec![],
204+
validator.public_key(),
205+
).expect(&format!("Validator {} should produce block", i));
206+
207+
// Verify VRF output is unique and non-zero
208+
assert_ne!(block.header.vrf_output, [0u8; 32],
209+
"Validator {} block should have non-zero VRF", i);
210+
211+
// Verify block is valid
212+
blockchain.validate_block(&block)
213+
.expect(&format!("Validator {} block should be valid", i));
214+
215+
blockchain.add_block(block).expect("Should add block");
216+
}
217+
}
218+
219+
/// Test VRF output distribution (outputs should appear random)
220+
#[test]
221+
fn test_vrf_output_distribution() {
222+
let sk = SecretKey::generate();
223+
224+
// Generate multiple VRF outputs with different messages
225+
let mut outputs = Vec::new();
226+
for i in 0..10 {
227+
let message = format!("message_{}", i);
228+
let (output, _) = sk.vrf_prove(message.as_bytes());
229+
outputs.push(output);
230+
}
231+
232+
// All outputs should be unique
233+
for i in 0..outputs.len() {
234+
for j in (i + 1)..outputs.len() {
235+
assert_ne!(outputs[i], outputs[j],
236+
"VRF output {} and {} should be different", i, j);
237+
}
238+
}
239+
240+
// Outputs should not be all zeros
241+
for (i, output) in outputs.iter().enumerate() {
242+
assert_ne!(output.as_bytes(), &[0u8; 32],
243+
"VRF output {} should not be all zeros", i);
244+
}
245+
}
246+
247+
/// Test VRF outputs are unpredictable without the secret key
248+
#[test]
249+
fn test_vrf_output_unpredictability() {
250+
let sk1 = SecretKey::generate();
251+
let sk2 = SecretKey::generate();
252+
253+
let message = b"predictable_message";
254+
255+
let (output1, _) = sk1.vrf_prove(message);
256+
let (output2, _) = sk2.vrf_prove(message);
257+
258+
// Even with same message, different keys produce unpredictable outputs
259+
assert_ne!(output1, output2);
260+
261+
// Outputs should not be trivially related to the message
262+
let message_hash = Hash256::from_bytes(
263+
sha2::Sha256::digest(message).into()
264+
);
265+
assert_ne!(output1.as_bytes(), message_hash.as_bytes());
266+
assert_ne!(output2.as_bytes(), message_hash.as_bytes());
267+
}
268+
269+
/// Test that VRF proofs are correctly serialized in blocks
270+
#[test]
271+
fn test_vrf_proof_serialization_in_blocks() {
272+
let sk = Arc::new(SecretKey::generate());
273+
let metrics = MetricsRegistry::new();
274+
let blockchain = Blockchain::new(sk.clone(), metrics);
275+
276+
let block = blockchain.produce_block(
277+
vec![],
278+
vec![],
279+
sk.public_key(),
280+
).unwrap();
281+
282+
// Verify VRF proof is not empty and has reasonable size
283+
assert!(!block.header.vrf_proof.is_empty(), "VRF proof should not be empty");
284+
assert!(block.header.vrf_proof.len() > 32, "VRF proof should have meaningful data");
285+
assert!(block.header.vrf_proof.len() < 1024, "VRF proof should be reasonably sized");
286+
287+
// Verify block validates (which includes VRF verification)
288+
blockchain.validate_block(&block).expect("Block with serialized VRF should validate");
289+
}
290+
291+
/// Test VRF with edge case: empty message
292+
#[test]
293+
fn test_vrf_empty_message() {
294+
let sk = SecretKey::generate();
295+
let pk = sk.public_key();
296+
297+
let message = b"";
298+
let (output, proof) = sk.vrf_prove(message);
299+
300+
// Should produce valid output even for empty message
301+
assert_ne!(output.as_bytes(), &[0u8; 32], "Empty message should still produce non-zero VRF output");
302+
303+
// Should verify correctly
304+
let verified = proof.verify(&pk, message)
305+
.expect("Empty message VRF should verify");
306+
assert_eq!(output, verified);
307+
}
308+
309+
/// Test VRF with edge case: very long message
310+
#[test]
311+
fn test_vrf_long_message() {
312+
let sk = SecretKey::generate();
313+
let pk = sk.public_key();
314+
315+
// Create a large message (10KB)
316+
let message = vec![0x42u8; 10000];
317+
let (output, proof) = sk.vrf_prove(&message);
318+
319+
// Should produce valid output for long message
320+
assert_ne!(output.as_bytes(), &[0u8; 32]);
321+
322+
// Should verify correctly
323+
let verified = proof.verify(&pk, &message)
324+
.expect("Long message VRF should verify");
325+
assert_eq!(output, verified);
326+
}
327+
328+
/// Test combining multiple VRF outputs for tournament seeding
329+
#[test]
330+
fn test_vrf_output_combination() {
331+
use bitcell_crypto::vrf::combine_vrf_outputs;
332+
333+
let sk1 = SecretKey::generate();
334+
let sk2 = SecretKey::generate();
335+
let sk3 = SecretKey::generate();
336+
337+
let (out1, _) = sk1.vrf_prove(b"round1");
338+
let (out2, _) = sk2.vrf_prove(b"round1");
339+
let (out3, _) = sk3.vrf_prove(b"round1");
340+
341+
let seed = combine_vrf_outputs(&[out1, out2, out3]);
342+
343+
// Combined seed should be non-zero
344+
assert_ne!(seed, Hash256::zero());
345+
346+
// Same outputs in different order should produce different seed
347+
let seed2 = combine_vrf_outputs(&[out2, out1, out3]);
348+
assert_ne!(seed, seed2, "Order should matter in VRF combination");
349+
350+
// Same outputs in same order should produce same seed
351+
let seed3 = combine_vrf_outputs(&[out1, out2, out3]);
352+
assert_eq!(seed, seed3, "Same outputs in same order should produce same seed");
353+
}

0 commit comments

Comments
 (0)