Skip to main content

MessageSession

Struct MessageSession 

Source
pub struct MessageSession { /* private fields */ }
Expand description

MessageSession manages the cryptographic state for secure message exchange between two parties using post-quantum cryptographic algorithms.

Each session contains:

  • A digital signature keypair for signing our messages
  • A verifier for validating messages from the other party
  • One chain key and one counter per direction, derived from the ML-KEM shared secret, so both parties can send at the same time without nonce reuse
  • A transcript hash of the handshake that every message signature is bound to

Every message is encrypted with its own key, derived from the chain key, after which the chain key moves forward and the old one is wiped. Someone who steals the session (or a stored to_bytes() copy) can’t decrypt the messages that came before.

Messages must be validated in the order they were crafted.

Implementations§

Source§

impl MessageSession

Source

pub fn to_bytes(&self) -> Zeroizing<Vec<u8>>

Serializes the session to a byte array

§Returns

The serialized session (wiped when dropped)

§Security Note

The serialized data contains sensitive cryptographic material including private keys. It should be stored securely and only deserialized in a trusted environment.

Source

pub fn from_bytes(bytes: &[u8]) -> Result<Self, CryptoError>

Deserializes a session from a byte array

§Arguments
  • bytes - The serialized session bytes
§Returns
  • Result<Self, CryptoError>: The deserialized session or an error
§Errors

Returns an error if the byte array is not the correct length, version or format

Source

pub fn new_initiator( my_signer: SignerPair, base_nonce: [u8; 24], target_prekey: &SignedPrekey, target_verifier: &PublicKeyBytes, ) -> Result<(Self, [u8; 1568]), CryptoError>

Creates a new session as the initiator

Send the responder everything it needs to call MessageSession::new_responder: the returned ciphertext, target_prekey.id(), the base nonce and your FN-DSA public key.

§Arguments
  • my_signer - Your own signer pair
  • base_nonce - Base nonce (0..16 session id, 16..24 counter), shared with the responder
  • target_prekey - A signed prekey of the target
  • target_verifier - FN-DSA public key of the target. Get it from a source you trust: it is what proves the prekey really belongs to the target.
§Returns
  • Result<(Self, [u8; pair::CIPHERTEXT_BYTES]), CryptoError>: The session and ciphertext for the responder, or InvalidSignature if the prekey was not signed by target_verifier
Examples found in repository?
examples/full_exchange.rs (lines 20-25)
7fn main() {
8    let alice_signer = SignerPair::create();
9    let mut bob_signer = SignerPair::create();
10
11    // Bob creates a one-time prekey and signs its public part, which he shares with Alice
12    let bob_prekey = KEMPair::create();
13    let bob_signed_prekey = SignedPrekey::new(&mut bob_signer, &bob_prekey).unwrap();
14
15    // Create a base nonce with a new session id, and a counter of 0
16    let base_nonce = create_nonce(&gen_session_id(), 0);
17
18    // Lets create the message session for Alice first. This checks that the prekey
19    // was signed by Bob.
20    let (mut alice_session, ciphertext) = MessageSession::new_initiator(
21        alice_signer.clone(),
22        base_nonce,
23        &bob_signed_prekey,
24        bob_signer.pub_key_bytes(), // Bob's public signer key
25    )
26    .unwrap();
27
28    // Now for Bob it would look like this
29    let mut bob_session = MessageSession::new_responder(
30        &bob_prekey,
31        bob_signer.clone(),
32        base_nonce,
33        &ciphertext,
34        alice_signer.pub_key_bytes(), // Alice's public signer key
35    )
36    .unwrap();
37
38    // The prekey was one-time, so Bob deletes it now (dropping it wipes it from memory)
39    drop(bob_prekey);
40
41    // Both sessions now hold one chain key per direction, derived from the shared secret.
42    // Every message gets its own key, and the chain moves forward after each one.
43
44    // Alice creates a message and prepares to send it to Bob
45    let message = b"Hello, Bob! This is a secret message.";
46    let encrypted_message = alice_session.craft_message(message).unwrap();
47
48    // Bob decrypts and verifies Alice's message
49    let raw_message = bob_session.validate_message(&encrypted_message).unwrap();
50
51    // Both message and raw_message are equal, let's print them out to illustrate
52    let message_str = String::from_utf8_lossy(message);
53    let raw_message_str = String::from_utf8_lossy(&raw_message);
54
55    println!("[1] Alice's message: {}", message_str);
56    println!("[2] Bob's decrypted message: {}", raw_message_str);
57
58    // Bob crafts a reply message to Alice
59    let reply = b"Hello, Alice! I received your message safely.";
60    let encrypted_reply = bob_session.craft_message(reply).unwrap();
61
62    // Alice decrypts and verifies Bob's reply
63    let raw_reply = alice_session.validate_message(&encrypted_reply).unwrap();
64
65    // Both reply and raw_reply are equal, let's print them again
66    let reply_str = String::from_utf8_lossy(reply);
67    let raw_reply_str = String::from_utf8_lossy(&raw_reply);
68
69    println!("[3] Bob's reply: {}", reply_str);
70    println!("[4] Alice's decrypted reply: {}", raw_reply_str);
71}
More examples
Hide additional examples
examples/prekey_server.rs (lines 54-59)
16fn main() {
17    let mut server = PrekeyServer::new();
18
19    // --- Bob's device: create prekeys, keep the secrets, publish the signed public parts
20    let mut bob_signer = SignerPair::create();
21    let bob_last_resort = KEMPair::create();
22    let bob_last_resort_signed = SignedPrekey::new(&mut bob_signer, &bob_last_resort).unwrap();
23
24    let mut bob_one_time: HashMap<PrekeyId, KEMPair> = HashMap::new();
25    let mut published = Vec::new();
26    for _ in 0..3 {
27        let prekey = KEMPair::create();
28        let signed = SignedPrekey::new(&mut bob_signer, &prekey).unwrap();
29        bob_one_time.insert(signed.id(), prekey);
30        published.push(signed);
31    }
32    server
33        .publish(
34            "bob",
35            *bob_signer.pub_key_bytes(),
36            bob_last_resort_signed.clone(),
37            published,
38        )
39        .unwrap();
40    println!(
41        "Bob published 3 one-time prekeys and a last-resort prekey ({} one-time left)",
42        server.one_time_remaining(&"bob")
43    );
44
45    // --- Alice's device: fetch Bob's bundle and start a session
46    let alice_signer = SignerPair::create();
47    let bundle = server.fetch(&"bob").unwrap();
48
49    // In a real app Alice checks Bob's identity key against a copy she trusts
50    // (for example by comparing safety numbers in person)
51    assert_eq!(&bundle.identity, bob_signer.pub_key_bytes());
52
53    let base_nonce = create_nonce(&gen_session_id(), 0);
54    let (mut alice_session, ciphertext) = MessageSession::new_initiator(
55        alice_signer.clone(),
56        base_nonce,
57        &bundle.prekey,
58        &bundle.identity,
59    )
60    .unwrap();
61
62    // Alice sends Bob: the ciphertext, the prekey id, the base nonce and her identity key
63    let prekey_id = bundle.prekey.id();
64
65    // --- Bob's device: find the prekey Alice used and set up his side
66    let mut bob_session = if let Some(prekey) = bob_one_time.remove(&prekey_id) {
67        // One-time prekey: it is removed from Bob's store above and wiped when dropped
68        // at the end of this block, which gives the session forward secrecy
69        MessageSession::new_responder(
70            &prekey,
71            bob_signer.clone(),
72            base_nonce,
73            &ciphertext,
74            alice_signer.pub_key_bytes(),
75        )
76        .unwrap()
77    } else if prekey_id == bob_last_resort_signed.id() {
78        // Last-resort prekey: kept until Bob rotates it
79        MessageSession::new_responder(
80            &bob_last_resort,
81            bob_signer.clone(),
82            base_nonce,
83            &ciphertext,
84            alice_signer.pub_key_bytes(),
85        )
86        .unwrap()
87    } else {
88        panic!("unknown prekey");
89    };
90    println!(
91        "Session set up; Bob has {} one-time prekey secrets left on his device",
92        bob_one_time.len()
93    );
94
95    // --- Talk
96    let encrypted = alice_session.craft_message(b"Hi Bob!").unwrap();
97    let message = bob_session.validate_message(&encrypted).unwrap();
98    println!("Bob received: {}", String::from_utf8_lossy(&message));
99
100    let encrypted = bob_session.craft_message(b"Hi Alice!").unwrap();
101    let reply = alice_session.validate_message(&encrypted).unwrap();
102    println!("Alice received: {}", String::from_utf8_lossy(&reply));
103}
Source

pub fn new_responder( my_prekey: &KEMPair, my_signer: SignerPair, base_nonce: [u8; 24], ciphertext: &[u8; 1568], sender_verifier: &PublicKeyBytes, ) -> Result<Self, CryptoError>

Creates a new session as the responder

If my_prekey is a one-time prekey, delete it everywhere you store it once this returns. That deletion is what gives the session forward secrecy.

§Arguments
  • my_prekey - The prekey the initiator used (look it up by the id they sent)
  • my_signer - Your own signer pair
  • base_nonce - Base nonce (0..16 session id, 16..24 counter), shared with the initiator
  • ciphertext - KEM ciphertext sent by the initiator
  • sender_verifier - FN-DSA public key of the initiator
§Returns
  • Result<Self, CryptoError>: The session or an error
Examples found in repository?
examples/full_exchange.rs (lines 29-35)
7fn main() {
8    let alice_signer = SignerPair::create();
9    let mut bob_signer = SignerPair::create();
10
11    // Bob creates a one-time prekey and signs its public part, which he shares with Alice
12    let bob_prekey = KEMPair::create();
13    let bob_signed_prekey = SignedPrekey::new(&mut bob_signer, &bob_prekey).unwrap();
14
15    // Create a base nonce with a new session id, and a counter of 0
16    let base_nonce = create_nonce(&gen_session_id(), 0);
17
18    // Lets create the message session for Alice first. This checks that the prekey
19    // was signed by Bob.
20    let (mut alice_session, ciphertext) = MessageSession::new_initiator(
21        alice_signer.clone(),
22        base_nonce,
23        &bob_signed_prekey,
24        bob_signer.pub_key_bytes(), // Bob's public signer key
25    )
26    .unwrap();
27
28    // Now for Bob it would look like this
29    let mut bob_session = MessageSession::new_responder(
30        &bob_prekey,
31        bob_signer.clone(),
32        base_nonce,
33        &ciphertext,
34        alice_signer.pub_key_bytes(), // Alice's public signer key
35    )
36    .unwrap();
37
38    // The prekey was one-time, so Bob deletes it now (dropping it wipes it from memory)
39    drop(bob_prekey);
40
41    // Both sessions now hold one chain key per direction, derived from the shared secret.
42    // Every message gets its own key, and the chain moves forward after each one.
43
44    // Alice creates a message and prepares to send it to Bob
45    let message = b"Hello, Bob! This is a secret message.";
46    let encrypted_message = alice_session.craft_message(message).unwrap();
47
48    // Bob decrypts and verifies Alice's message
49    let raw_message = bob_session.validate_message(&encrypted_message).unwrap();
50
51    // Both message and raw_message are equal, let's print them out to illustrate
52    let message_str = String::from_utf8_lossy(message);
53    let raw_message_str = String::from_utf8_lossy(&raw_message);
54
55    println!("[1] Alice's message: {}", message_str);
56    println!("[2] Bob's decrypted message: {}", raw_message_str);
57
58    // Bob crafts a reply message to Alice
59    let reply = b"Hello, Alice! I received your message safely.";
60    let encrypted_reply = bob_session.craft_message(reply).unwrap();
61
62    // Alice decrypts and verifies Bob's reply
63    let raw_reply = alice_session.validate_message(&encrypted_reply).unwrap();
64
65    // Both reply and raw_reply are equal, let's print them again
66    let reply_str = String::from_utf8_lossy(reply);
67    let raw_reply_str = String::from_utf8_lossy(&raw_reply);
68
69    println!("[3] Bob's reply: {}", reply_str);
70    println!("[4] Alice's decrypted reply: {}", raw_reply_str);
71}
More examples
Hide additional examples
examples/prekey_server.rs (lines 69-75)
16fn main() {
17    let mut server = PrekeyServer::new();
18
19    // --- Bob's device: create prekeys, keep the secrets, publish the signed public parts
20    let mut bob_signer = SignerPair::create();
21    let bob_last_resort = KEMPair::create();
22    let bob_last_resort_signed = SignedPrekey::new(&mut bob_signer, &bob_last_resort).unwrap();
23
24    let mut bob_one_time: HashMap<PrekeyId, KEMPair> = HashMap::new();
25    let mut published = Vec::new();
26    for _ in 0..3 {
27        let prekey = KEMPair::create();
28        let signed = SignedPrekey::new(&mut bob_signer, &prekey).unwrap();
29        bob_one_time.insert(signed.id(), prekey);
30        published.push(signed);
31    }
32    server
33        .publish(
34            "bob",
35            *bob_signer.pub_key_bytes(),
36            bob_last_resort_signed.clone(),
37            published,
38        )
39        .unwrap();
40    println!(
41        "Bob published 3 one-time prekeys and a last-resort prekey ({} one-time left)",
42        server.one_time_remaining(&"bob")
43    );
44
45    // --- Alice's device: fetch Bob's bundle and start a session
46    let alice_signer = SignerPair::create();
47    let bundle = server.fetch(&"bob").unwrap();
48
49    // In a real app Alice checks Bob's identity key against a copy she trusts
50    // (for example by comparing safety numbers in person)
51    assert_eq!(&bundle.identity, bob_signer.pub_key_bytes());
52
53    let base_nonce = create_nonce(&gen_session_id(), 0);
54    let (mut alice_session, ciphertext) = MessageSession::new_initiator(
55        alice_signer.clone(),
56        base_nonce,
57        &bundle.prekey,
58        &bundle.identity,
59    )
60    .unwrap();
61
62    // Alice sends Bob: the ciphertext, the prekey id, the base nonce and her identity key
63    let prekey_id = bundle.prekey.id();
64
65    // --- Bob's device: find the prekey Alice used and set up his side
66    let mut bob_session = if let Some(prekey) = bob_one_time.remove(&prekey_id) {
67        // One-time prekey: it is removed from Bob's store above and wiped when dropped
68        // at the end of this block, which gives the session forward secrecy
69        MessageSession::new_responder(
70            &prekey,
71            bob_signer.clone(),
72            base_nonce,
73            &ciphertext,
74            alice_signer.pub_key_bytes(),
75        )
76        .unwrap()
77    } else if prekey_id == bob_last_resort_signed.id() {
78        // Last-resort prekey: kept until Bob rotates it
79        MessageSession::new_responder(
80            &bob_last_resort,
81            bob_signer.clone(),
82            base_nonce,
83            &ciphertext,
84            alice_signer.pub_key_bytes(),
85        )
86        .unwrap()
87    } else {
88        panic!("unknown prekey");
89    };
90    println!(
91        "Session set up; Bob has {} one-time prekey secrets left on his device",
92        bob_one_time.len()
93    );
94
95    // --- Talk
96    let encrypted = alice_session.craft_message(b"Hi Bob!").unwrap();
97    let message = bob_session.validate_message(&encrypted).unwrap();
98    println!("Bob received: {}", String::from_utf8_lossy(&message));
99
100    let encrypted = bob_session.craft_message(b"Hi Alice!").unwrap();
101    let reply = alice_session.validate_message(&encrypted).unwrap();
102    println!("Alice received: {}", String::from_utf8_lossy(&reply));
103}
Source

pub fn craft_message(&mut self, message: &[u8]) -> Result<Vec<u8>, CryptoError>

Creates a signed and encrypted message for the other party

§Arguments
  • message - The plaintext message to encrypt
§Returns
  • Result<Vec<u8>, CryptoError>: The encrypted message or an error
§Security Note

This method increments the send counter to ensure a unique nonce for each message, and fails with NonceExhausted instead of ever reusing one.

Examples found in repository?
examples/full_exchange.rs (line 46)
7fn main() {
8    let alice_signer = SignerPair::create();
9    let mut bob_signer = SignerPair::create();
10
11    // Bob creates a one-time prekey and signs its public part, which he shares with Alice
12    let bob_prekey = KEMPair::create();
13    let bob_signed_prekey = SignedPrekey::new(&mut bob_signer, &bob_prekey).unwrap();
14
15    // Create a base nonce with a new session id, and a counter of 0
16    let base_nonce = create_nonce(&gen_session_id(), 0);
17
18    // Lets create the message session for Alice first. This checks that the prekey
19    // was signed by Bob.
20    let (mut alice_session, ciphertext) = MessageSession::new_initiator(
21        alice_signer.clone(),
22        base_nonce,
23        &bob_signed_prekey,
24        bob_signer.pub_key_bytes(), // Bob's public signer key
25    )
26    .unwrap();
27
28    // Now for Bob it would look like this
29    let mut bob_session = MessageSession::new_responder(
30        &bob_prekey,
31        bob_signer.clone(),
32        base_nonce,
33        &ciphertext,
34        alice_signer.pub_key_bytes(), // Alice's public signer key
35    )
36    .unwrap();
37
38    // The prekey was one-time, so Bob deletes it now (dropping it wipes it from memory)
39    drop(bob_prekey);
40
41    // Both sessions now hold one chain key per direction, derived from the shared secret.
42    // Every message gets its own key, and the chain moves forward after each one.
43
44    // Alice creates a message and prepares to send it to Bob
45    let message = b"Hello, Bob! This is a secret message.";
46    let encrypted_message = alice_session.craft_message(message).unwrap();
47
48    // Bob decrypts and verifies Alice's message
49    let raw_message = bob_session.validate_message(&encrypted_message).unwrap();
50
51    // Both message and raw_message are equal, let's print them out to illustrate
52    let message_str = String::from_utf8_lossy(message);
53    let raw_message_str = String::from_utf8_lossy(&raw_message);
54
55    println!("[1] Alice's message: {}", message_str);
56    println!("[2] Bob's decrypted message: {}", raw_message_str);
57
58    // Bob crafts a reply message to Alice
59    let reply = b"Hello, Alice! I received your message safely.";
60    let encrypted_reply = bob_session.craft_message(reply).unwrap();
61
62    // Alice decrypts and verifies Bob's reply
63    let raw_reply = alice_session.validate_message(&encrypted_reply).unwrap();
64
65    // Both reply and raw_reply are equal, let's print them again
66    let reply_str = String::from_utf8_lossy(reply);
67    let raw_reply_str = String::from_utf8_lossy(&raw_reply);
68
69    println!("[3] Bob's reply: {}", reply_str);
70    println!("[4] Alice's decrypted reply: {}", raw_reply_str);
71}
More examples
Hide additional examples
examples/prekey_server.rs (line 96)
16fn main() {
17    let mut server = PrekeyServer::new();
18
19    // --- Bob's device: create prekeys, keep the secrets, publish the signed public parts
20    let mut bob_signer = SignerPair::create();
21    let bob_last_resort = KEMPair::create();
22    let bob_last_resort_signed = SignedPrekey::new(&mut bob_signer, &bob_last_resort).unwrap();
23
24    let mut bob_one_time: HashMap<PrekeyId, KEMPair> = HashMap::new();
25    let mut published = Vec::new();
26    for _ in 0..3 {
27        let prekey = KEMPair::create();
28        let signed = SignedPrekey::new(&mut bob_signer, &prekey).unwrap();
29        bob_one_time.insert(signed.id(), prekey);
30        published.push(signed);
31    }
32    server
33        .publish(
34            "bob",
35            *bob_signer.pub_key_bytes(),
36            bob_last_resort_signed.clone(),
37            published,
38        )
39        .unwrap();
40    println!(
41        "Bob published 3 one-time prekeys and a last-resort prekey ({} one-time left)",
42        server.one_time_remaining(&"bob")
43    );
44
45    // --- Alice's device: fetch Bob's bundle and start a session
46    let alice_signer = SignerPair::create();
47    let bundle = server.fetch(&"bob").unwrap();
48
49    // In a real app Alice checks Bob's identity key against a copy she trusts
50    // (for example by comparing safety numbers in person)
51    assert_eq!(&bundle.identity, bob_signer.pub_key_bytes());
52
53    let base_nonce = create_nonce(&gen_session_id(), 0);
54    let (mut alice_session, ciphertext) = MessageSession::new_initiator(
55        alice_signer.clone(),
56        base_nonce,
57        &bundle.prekey,
58        &bundle.identity,
59    )
60    .unwrap();
61
62    // Alice sends Bob: the ciphertext, the prekey id, the base nonce and her identity key
63    let prekey_id = bundle.prekey.id();
64
65    // --- Bob's device: find the prekey Alice used and set up his side
66    let mut bob_session = if let Some(prekey) = bob_one_time.remove(&prekey_id) {
67        // One-time prekey: it is removed from Bob's store above and wiped when dropped
68        // at the end of this block, which gives the session forward secrecy
69        MessageSession::new_responder(
70            &prekey,
71            bob_signer.clone(),
72            base_nonce,
73            &ciphertext,
74            alice_signer.pub_key_bytes(),
75        )
76        .unwrap()
77    } else if prekey_id == bob_last_resort_signed.id() {
78        // Last-resort prekey: kept until Bob rotates it
79        MessageSession::new_responder(
80            &bob_last_resort,
81            bob_signer.clone(),
82            base_nonce,
83            &ciphertext,
84            alice_signer.pub_key_bytes(),
85        )
86        .unwrap()
87    } else {
88        panic!("unknown prekey");
89    };
90    println!(
91        "Session set up; Bob has {} one-time prekey secrets left on his device",
92        bob_one_time.len()
93    );
94
95    // --- Talk
96    let encrypted = alice_session.craft_message(b"Hi Bob!").unwrap();
97    let message = bob_session.validate_message(&encrypted).unwrap();
98    println!("Bob received: {}", String::from_utf8_lossy(&message));
99
100    let encrypted = bob_session.craft_message(b"Hi Alice!").unwrap();
101    let reply = alice_session.validate_message(&encrypted).unwrap();
102    println!("Alice received: {}", String::from_utf8_lossy(&reply));
103}
Source

pub fn validate_message( &mut self, ciphertext: &[u8], ) -> Result<Vec<u8>, CryptoError>

Decrypts and validates a message from the other party

§Arguments
  • ciphertext - The encrypted message
§Returns
  • Result<Vec<u8>, CryptoError>: The decrypted and validated message or an error
§Security Note

Messages must arrive in the order they were crafted. The receive counter only advances for authentic messages, so replayed or forged input is rejected without desynchronizing the session.

Examples found in repository?
examples/full_exchange.rs (line 49)
7fn main() {
8    let alice_signer = SignerPair::create();
9    let mut bob_signer = SignerPair::create();
10
11    // Bob creates a one-time prekey and signs its public part, which he shares with Alice
12    let bob_prekey = KEMPair::create();
13    let bob_signed_prekey = SignedPrekey::new(&mut bob_signer, &bob_prekey).unwrap();
14
15    // Create a base nonce with a new session id, and a counter of 0
16    let base_nonce = create_nonce(&gen_session_id(), 0);
17
18    // Lets create the message session for Alice first. This checks that the prekey
19    // was signed by Bob.
20    let (mut alice_session, ciphertext) = MessageSession::new_initiator(
21        alice_signer.clone(),
22        base_nonce,
23        &bob_signed_prekey,
24        bob_signer.pub_key_bytes(), // Bob's public signer key
25    )
26    .unwrap();
27
28    // Now for Bob it would look like this
29    let mut bob_session = MessageSession::new_responder(
30        &bob_prekey,
31        bob_signer.clone(),
32        base_nonce,
33        &ciphertext,
34        alice_signer.pub_key_bytes(), // Alice's public signer key
35    )
36    .unwrap();
37
38    // The prekey was one-time, so Bob deletes it now (dropping it wipes it from memory)
39    drop(bob_prekey);
40
41    // Both sessions now hold one chain key per direction, derived from the shared secret.
42    // Every message gets its own key, and the chain moves forward after each one.
43
44    // Alice creates a message and prepares to send it to Bob
45    let message = b"Hello, Bob! This is a secret message.";
46    let encrypted_message = alice_session.craft_message(message).unwrap();
47
48    // Bob decrypts and verifies Alice's message
49    let raw_message = bob_session.validate_message(&encrypted_message).unwrap();
50
51    // Both message and raw_message are equal, let's print them out to illustrate
52    let message_str = String::from_utf8_lossy(message);
53    let raw_message_str = String::from_utf8_lossy(&raw_message);
54
55    println!("[1] Alice's message: {}", message_str);
56    println!("[2] Bob's decrypted message: {}", raw_message_str);
57
58    // Bob crafts a reply message to Alice
59    let reply = b"Hello, Alice! I received your message safely.";
60    let encrypted_reply = bob_session.craft_message(reply).unwrap();
61
62    // Alice decrypts and verifies Bob's reply
63    let raw_reply = alice_session.validate_message(&encrypted_reply).unwrap();
64
65    // Both reply and raw_reply are equal, let's print them again
66    let reply_str = String::from_utf8_lossy(reply);
67    let raw_reply_str = String::from_utf8_lossy(&raw_reply);
68
69    println!("[3] Bob's reply: {}", reply_str);
70    println!("[4] Alice's decrypted reply: {}", raw_reply_str);
71}
More examples
Hide additional examples
examples/prekey_server.rs (line 97)
16fn main() {
17    let mut server = PrekeyServer::new();
18
19    // --- Bob's device: create prekeys, keep the secrets, publish the signed public parts
20    let mut bob_signer = SignerPair::create();
21    let bob_last_resort = KEMPair::create();
22    let bob_last_resort_signed = SignedPrekey::new(&mut bob_signer, &bob_last_resort).unwrap();
23
24    let mut bob_one_time: HashMap<PrekeyId, KEMPair> = HashMap::new();
25    let mut published = Vec::new();
26    for _ in 0..3 {
27        let prekey = KEMPair::create();
28        let signed = SignedPrekey::new(&mut bob_signer, &prekey).unwrap();
29        bob_one_time.insert(signed.id(), prekey);
30        published.push(signed);
31    }
32    server
33        .publish(
34            "bob",
35            *bob_signer.pub_key_bytes(),
36            bob_last_resort_signed.clone(),
37            published,
38        )
39        .unwrap();
40    println!(
41        "Bob published 3 one-time prekeys and a last-resort prekey ({} one-time left)",
42        server.one_time_remaining(&"bob")
43    );
44
45    // --- Alice's device: fetch Bob's bundle and start a session
46    let alice_signer = SignerPair::create();
47    let bundle = server.fetch(&"bob").unwrap();
48
49    // In a real app Alice checks Bob's identity key against a copy she trusts
50    // (for example by comparing safety numbers in person)
51    assert_eq!(&bundle.identity, bob_signer.pub_key_bytes());
52
53    let base_nonce = create_nonce(&gen_session_id(), 0);
54    let (mut alice_session, ciphertext) = MessageSession::new_initiator(
55        alice_signer.clone(),
56        base_nonce,
57        &bundle.prekey,
58        &bundle.identity,
59    )
60    .unwrap();
61
62    // Alice sends Bob: the ciphertext, the prekey id, the base nonce and her identity key
63    let prekey_id = bundle.prekey.id();
64
65    // --- Bob's device: find the prekey Alice used and set up his side
66    let mut bob_session = if let Some(prekey) = bob_one_time.remove(&prekey_id) {
67        // One-time prekey: it is removed from Bob's store above and wiped when dropped
68        // at the end of this block, which gives the session forward secrecy
69        MessageSession::new_responder(
70            &prekey,
71            bob_signer.clone(),
72            base_nonce,
73            &ciphertext,
74            alice_signer.pub_key_bytes(),
75        )
76        .unwrap()
77    } else if prekey_id == bob_last_resort_signed.id() {
78        // Last-resort prekey: kept until Bob rotates it
79        MessageSession::new_responder(
80            &bob_last_resort,
81            bob_signer.clone(),
82            base_nonce,
83            &ciphertext,
84            alice_signer.pub_key_bytes(),
85        )
86        .unwrap()
87    } else {
88        panic!("unknown prekey");
89    };
90    println!(
91        "Session set up; Bob has {} one-time prekey secrets left on his device",
92        bob_one_time.len()
93    );
94
95    // --- Talk
96    let encrypted = alice_session.craft_message(b"Hi Bob!").unwrap();
97    let message = bob_session.validate_message(&encrypted).unwrap();
98    println!("Bob received: {}", String::from_utf8_lossy(&message));
99
100    let encrypted = bob_session.craft_message(b"Hi Alice!").unwrap();
101    let reply = alice_session.validate_message(&encrypted).unwrap();
102    println!("Alice received: {}", String::from_utf8_lossy(&reply));
103}
Source

pub fn send_counter(&self) -> u64

Gets the counter of the last message sent

Source

pub fn recv_counter(&self) -> u64

Gets the counter of the last message received

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.