An implementation of Olm and Megolm in pure Rust.

Overview

A Rust implementation of Olm and Megolm

vodozemac is a Rust implementation of libolm, a cryptographic library used for end-to-end encryption in Matrix. At its core, vodozemac is an implementation of the Olm and Megolm cryptographic ratchets, along with a high-level API for easily establishing cryptographic communication channels with other parties.

Olm

Olm is an implementation of the Double Ratchet algorithm, very similar to that employed by the Signal Protocol. It allows the establishment of a 1-to-1 private communication channel, with perfect forward secrecy and self-healing properties.

A detailed technical specification can be found at https://gitlab.matrix.org/matrix-org/olm/-/blob/master/docs/olm.md.

Overview

The core component of the crate is the Account, representing a single Olm participant. An Olm Account consists of a collection of key pairs, though often documentation shortens this by just saying "keys". These are:

  1. An Ed25519 signing key pair representing the stable cryptographic identity of the participant (the participant's "fingerprint").
  2. A Curve25519 sender key pair (also sometimes called the identity key pair, somewhat confusingly).
  3. A number of one-time key pairs.
  4. A current and previous (if any) "fallback" key pair.

While the key in 1 is used for signing but not encryption, the keys in 2-4 participate in a triple Diffie-Hellman key exchange (3DH) with another Olm participant, thereby establishing an Olm session on each side of the communication channel. Ultimately, this session is used for deriving the concrete encryption keys for a particular message.

Olm sessions are represented by the Session struct. Such a session is created by calling Account::create_outbound_session on one of the participating accounts, passing it the Curve25519 sender key and one Curve25519 one-time key of the other side. The protocol is asynchronous, so the participant can start sending messages to the other side even before the other side has created a session, producing so-called pre-key messages (see PreKeyMessage).

Once the other participant receives such a pre-key message, they can create their own matching session by calling Account::create_inbound_session and passing it the pre-key message they received and the Curve25519 sender key of the other side. This completes the establishment of the Olm communication channel.

    use anyhow::Result;
    use vodozemac::{Account, messages::OlmMessage};

    fn main() -> Result<()> {
        let alice = Account::new();
        let mut bob = Account::new();

        bob.generate_one_time_keys(1);
        let bob_otk = *bob.one_time_keys().values().next().unwrap();

        let mut alice_session = alice
            .create_outbound_session(*bob.curve25519_key(), bob_otk);

        bob.mark_keys_as_published();

        let message = "Keep it between us, OK?";
        let alice_msg = alice_session.encrypt(message);

        if let OlmMessage::PreKey(m) = alice_msg.clone() {
            let mut bob_session = bob
                .create_inbound_session(alice.curve25519_key(), &m)?;

            assert_eq!(alice_session.session_id(), bob_session.session_id());

            let what_bob_received = bob_session.decrypt(&alice_msg)?;
            assert_eq!(message, what_bob_received);

            let bob_reply = "Yes. Take this, it's dangerous out there!";
            let bob_encrypted_reply = bob_session.encrypt(bob_reply).into();

            let what_alice_received = alice_session
                .decrypt(&bob_encrypted_reply)?;
            assert_eq!(&what_alice_received, bob_reply);
        }

        Ok(())
    }

Sending messages

To encrypt a message, just call Session::encrypt(msg_content). This will either produce an OlmMessage::PreKey(..) or OlmMessage::Normal(..) depending on whether the session is fully established. A session is fully established once you receive (and decrypt) at least one message from the other side.

Pickling

vodozemac (will soon) supports pickling of both Account and Session, in which the entire state contained within is serialized into a form called a "pickle". Subsequently, accounts and sessions can be restored from a pickle ("unpickled") in order to continue operation. This is used to support some Matrix features like device dehydration.

Legacy pickles

The legacy pickle format is a simple binary format used by libolm. Currently unimplemented, but will need to be implemented for interoperability with legacy clients using libolm.

Modern pickles

The pickle format used by this crate. The exact format is currently undecided, but is likely to be based on Protocol Buffers. For now, we're pickling to JSON. Also unimplemented at the moment in the repository but will be added shortly.

Megolm

Megolm is an AES-based single ratchet for group conversations with a large number of participants, where using Olm would be cost prohibitive, (because it would imply establishing a pairwise channel between each pair of participants).

This is a trade-off in which we lose Olm's self-healing properties, because someone in possession of a Megolm session at a particular state can derive all future states. However, if the attacker is only able to obtain the session in a ratcheted state, they cannot use it to decrypt messages encrypted with an earlier state. This preserves forward secrecy.

A detailed technical specification can be found at https://gitlab.matrix.org/matrix-org/olm/-/blob/master/docs/megolm.md.

Vendored libraries

vodozemac currently vendors olm-rs to provide a fixed version of the SAS MAC calculation method, calculate_mac_fixed_base64. This is used solely for implementing correctness tests against libolm and will be removed once the fixed method has been exposed in upstream olm-rs.

Comments
  • feat: Expose encrypting and decrypting bytes

    feat: Expose encrypting and decrypting bytes

    This is a proposal to allow using bytes directly without extra conversion steps.

    Use case: I am using protobuf encoded messages and encrypt them with Olm. Now if I want to decrypt an Olm message vodozemac will decrypt the message convert bytes into string and return it to me. Me, in turn, need to convert string back into bytes and then decode my protobuf message. The same thing happens when encoding a message.

    What do you think? Current implementation breaks InboundCreationResult type for implementation simplicity.

    opened by zaynetro 3
  • Encoding issue with GroupSession

    Encoding issue with GroupSession

    Describe the bug

    I believe that there is an encoding issue with the GroupSession messages.

    To Reproduce Steps to reproduce the behavior:

    fn test(payload: &str) -> anyhow::Result<()> {
        let outbound = vodozemac::megolm::GroupSession::new();
    
        let json = serde_json::to_string(&outbound.pickle())?;
        let mut outbound: vodozemac::megolm::GroupSession =
            serde_json::from_str::<vodozemac::megolm::GroupSessionPickle>(&json)?.into();
    
        let session_key = outbound.session_key().to_base64();
        let inbound = olm_rs::inbound_group_session::OlmInboundGroupSession::new(&session_key)?;
    
        let mut i = 10;
        let msg = loop {
            let msg = outbound.encrypt(payload).to_bytes();
    
            i -= 1;
            if i == 0 {
                break base64::encode(&msg);
            }
        };
    
        let _msg = inbound.decrypt(msg)?;
    
        //assert_eq!(payload, msg.0);
        //println!("Message: {msg:?}");
    
        Ok(())
    }
    
    fn main() {
        for i in 0..256 {
            let payload = "0".repeat(i);
            println!("{i}: {}", if test(&payload).is_ok() { "Ok" } else { "Err" });
        }
    }
    

    Expected behavior All messages decode properly.

    Screenshots

    Log output
    0: Ok
    1: Ok
    2: Ok
    3: Ok
    4: Ok
    5: Ok
    6: Ok
    7: Ok
    8: Ok
    9: Ok
    10: Ok
    11: Ok
    12: Ok
    13: Ok
    14: Ok
    15: Ok
    16: Err
    17: Err
    18: Err
    19: Err
    20: Err
    21: Err
    22: Err
    23: Err
    24: Err
    25: Err
    26: Err
    27: Err
    28: Err
    29: Err
    30: Err
    31: Err
    32: Err
    33: Err
    34: Err
    35: Err
    36: Err
    37: Err
    38: Err
    39: Err
    40: Err
    41: Err
    42: Err
    43: Err
    44: Err
    45: Err
    46: Err
    47: Err
    48: Ok
    49: Ok
    50: Ok
    51: Ok
    52: Ok
    53: Ok
    54: Ok
    55: Ok
    56: Ok
    57: Ok
    58: Ok
    59: Ok
    60: Ok
    61: Ok
    62: Ok
    63: Ok
    64: Err
    65: Err
    66: Err
    67: Err
    68: Err
    69: Err
    70: Err
    71: Err
    72: Err
    73: Err
    74: Err
    75: Err
    76: Err
    77: Err
    78: Err
    79: Err
    80: Err
    81: Err
    82: Err
    83: Err
    84: Err
    85: Err
    86: Err
    87: Err
    88: Err
    89: Err
    90: Err
    91: Err
    92: Err
    93: Err
    94: Err
    95: Err
    96: Ok
    97: Ok
    98: Ok
    99: Ok
    100: Ok
    101: Ok
    102: Ok
    103: Ok
    104: Ok
    105: Ok
    106: Ok
    107: Ok
    108: Ok
    109: Ok
    110: Ok
    111: Ok
    112: Err
    113: Err
    114: Err
    115: Err
    116: Err
    117: Err
    118: Err
    119: Err
    120: Err
    121: Err
    122: Err
    123: Err
    124: Err
    125: Err
    126: Err
    127: Err
    128: Ok
    129: Ok
    130: Ok
    131: Ok
    132: Ok
    133: Ok
    134: Ok
    135: Ok
    136: Ok
    137: Ok
    138: Ok
    139: Ok
    140: Ok
    141: Ok
    142: Ok
    143: Ok
    144: Err
    145: Err
    146: Err
    147: Err
    148: Err
    149: Err
    150: Err
    151: Err
    152: Err
    153: Err
    154: Err
    155: Err
    156: Err
    157: Err
    158: Err
    159: Err
    160: Err
    161: Err
    162: Err
    163: Err
    164: Err
    165: Err
    166: Err
    167: Err
    168: Err
    169: Err
    170: Err
    171: Err
    172: Err
    173: Err
    174: Err
    175: Err
    176: Ok
    177: Ok
    178: Ok
    179: Ok
    180: Ok
    181: Ok
    182: Ok
    183: Ok
    184: Ok
    185: Ok
    186: Ok
    187: Ok
    188: Ok
    189: Ok
    190: Ok
    191: Ok
    192: Err
    193: Err
    194: Err
    195: Err
    196: Err
    197: Err
    198: Err
    199: Err
    200: Err
    201: Err
    202: Err
    203: Err
    204: Err
    205: Err
    206: Err
    207: Err
    208: Err
    209: Err
    210: Err
    211: Err
    212: Err
    213: Err
    214: Err
    215: Err
    216: Err
    217: Err
    218: Err
    219: Err
    220: Err
    221: Err
    222: Err
    223: Err
    224: Ok
    225: Ok
    226: Ok
    227: Ok
    228: Ok
    229: Ok
    230: Ok
    231: Ok
    232: Ok
    233: Ok
    234: Ok
    235: Ok
    236: Ok
    237: Ok
    238: Ok
    239: Ok
    240: Err
    241: Err
    242: Err
    243: Err
    244: Err
    245: Err
    246: Err
    247: Err
    248: Err
    249: Err
    250: Err
    251: Err
    252: Err
    253: Err
    254: Err
    255: Err
    

    Additional context

    The reverse test (encoding with libolm and decoding with vodozemac) works all the time.

    opened by ctron 2
  • vodozemac: Switch to bincode to decode libolm pickles

    vodozemac: Switch to bincode to decode libolm pickles

    This PR switches towards using the bincode crate to decode libolm pickles. This requires a bincode patch, since bincode encodes slice lengths as u64 while libolm as u32.

    opened by poljar 2
  • Fix OTK pickling

    Fix OTK pickling

    We remove the OTKs from the public_keys map once they're published, but we need to keep the entries in reverse_public_keys for as long as they're still in private_keys.

    Not sure if we want to rename reverse_public_keys?

    opened by erikjohnston 2
  • Initial fuzzing setup

    Initial fuzzing setup

    This PR introduces an AFL based fuzzing setup for vodozemac.

    Not many things are yet fuzzed, a comprehensive list of codepaths we'll want to fuzz:

    opened by poljar 2
  • Fix rust-analyzer

    Fix rust-analyzer

    This patch fixes rust-analyzer on vscode, by temporarily patching the requirements to a commit version of ed25519-dalek

    You can see the differences here: https://github.com/dalek-cryptography/ed25519-dalek/compare/1.0.1...ad461f4f0f56507a2945510dedb914b3d3547c40

    The following difference is what makes this patch workable;

    -#![cfg(not(test))]
    -#![forbid(unsafe_code)]
    +#![cfg_attr(not(test), forbid(unsafe_code))]
    

    From https://github.com/dalek-cryptography/ed25519-dalek/issues/173;

    Yes since this was added in 1.0.1, rust-analyzer is not happy since it compiles everything in test mode

    This should be applied as long as ed25519-dalek 1.1 isn't out, or this crate has to be published to crates.io

    opened by ShadowJonathan 2
  • Mutation testing

    Mutation testing

    Mutation testing using cargo-mutants reveals a bunch of test cases that aren't checking for all the code behavior we should.

    Once we fix all those discovered issues, we should set up cargo-mutants to run as a daily CI job: https://github.com/sourcefrog/cargo-mutants#continuous-integration

    • [ ] - Fix issues discovered by mutation testing
    • [ ] - Set up cargo-mutant in the CI

    Full cargo-mutant output follows:

    cargo mutants
    Freshen source tree ... ok in 0.051s
    Copy source and build products to scratch directory ... 1917 MB in 0.639s
    Unmutated baseline ... ok in 13.512s
    Auto-set test timeout to 20.0s
    Found 393 mutants to test
    src/sas.rs:129: replace <impl Debug for EstablishedSas>::fmt -> std::fmt::Result with Ok(Default::default()) ... NOT CAUGHT in 4.381s
    src/olm/session/message_key.rs:65: replace MessageKey::key -> &[u8 ; 32] with Default::default() ... NOT CAUGHT in 4.405s
    src/olm/session/mod.rs:239: replace Session::next_message_key -> MessageKey with Default::default() ... NOT CAUGHT in 4.225s
    src/olm/session/message_key.rs:77: replace MessageKey::index -> u64 with Default::default() ... NOT CAUGHT in 3.954s
    src/types/ed25519.rs:276: replace Ed25519Signature::to_base64 -> String with "".into() ... NOT CAUGHT in 3.955s
    src/megolm/message.rs:151: replace MegolmMessage::encrypt -> MegolmMessage with Default::default() ... NOT CAUGHT in 3.988s
    src/olm/session/receiver_chain.rs:55: replace MessageKeyStore::remove_message_key with () ... NOT CAUGHT in 4.156s
    src/olm/session/mod.rs:87: replace ChainStore::is_empty -> bool with true ... NOT CAUGHT in 4.206s
    src/olm/account/mod.rs:195: replace Account::remove_one_time_key -> Option<Curve25519SecretKey> with Default::default() ... NOT CAUGHT in 4.182s
    src/sas.rs:159: replace SasBytes::decimals -> (u16, u16, u16) with Default::default() ... NOT CAUGHT in 4.275s
    src/olm/messages/mod.rs:98: replace OlmMessage::message -> &[u8] with Default::default() ... NOT CAUGHT in 4.140s
    src/types/mod.rs:31: replace <impl From for String>::from -> String with "".into() ... NOT CAUGHT in 4.024s
    src/olm/messages/message.rs:53: replace Message::ciphertext -> &[u8] with Default::default() ... NOT CAUGHT in 4.241s
    src/types/mod.rs:37: replace KeyId::to_base64 -> String with "xyzzy".into() ... NOT CAUGHT in 4.275s
    src/sas.rs:151: replace SasBytes::emoji_indices -> [u8 ; 7] with Default::default() ... NOT CAUGHT in 4.008s
    src/megolm/inbound_group_session.rs:192: replace InboundGroupSession::get_cipher_at -> Option<Cipher> with Default::default() ... NOT CAUGHT in 4.310s
    src/olm/messages/message.rs:48: replace Message::chain_index -> u64 with Default::default() ... NOT CAUGHT in 3.974s
    src/olm/account/mod.rs:138: replace Account::max_number_of_one_time_keys -> usize with Default::default() ... NOT CAUGHT in 4.317s
    src/types/ed25519.rs:276: replace Ed25519Signature::to_base64 -> String with "xyzzy".into() ... NOT CAUGHT in 4.305s
    src/olm/account/mod.rs:302: replace Account::forget_fallback_key -> bool with true ... NOT CAUGHT in 4.190s
    src/megolm/message.rs:127: replace MegolmMessage::add_signature -> Result<(), SignatureError> with Ok(Default::default()) ... NOT CAUGHT in 4.224s
    src/olm/session/mod.rs:148: replace <impl Debug for Session>::fmt -> std::fmt::Result with Ok(Default::default()) ... NOT CAUGHT in 3.972s
    src/types/ed25519.rs:118: replace Ed25519SecretKey::from_base64 -> Result<Self, crate::KeyError> with Ok(Default::default()) ... NOT CAUGHT in 4.374s
    src/megolm/message.rs:53: replace MegolmMessage::message_index -> u32 with Default::default() ... NOT CAUGHT in 4.239s
    src/types/ed25519.rs:250: replace <impl Debug for Ed25519PublicKey>::fmt -> std::fmt::Result with Ok(Default::default()) ... NOT CAUGHT in 3.980s
    src/olm/account/mod.rs:307: replace Account::mark_keys_as_published with () ... NOT CAUGHT in 4.270s
    src/olm/session/message_key.rs:28: replace <impl Drop for MessageKey>::drop with () ... NOT CAUGHT in 4.271s
    src/types/ed25519.rs:100: replace Ed25519SecretKey::from_slice -> Result<Self, crate::KeyError> with Ok(Default::default()) ... NOT CAUGHT in 4.259s
    src/olm/account/mod.rs:302: replace Account::forget_fallback_key -> bool with false ... NOT CAUGHT in 4.273s
    src/olm/account/fallback_keys.rs:93: replace FallbackKeys::forget_previous_fallback_key -> Option<FallbackKey> with Default::default() ... NOT CAUGHT in 4.260s
    src/olm/session/chain_key.rs:79: replace RemoteChainKey::advance with () ... TIMEOUT in 21.578s
    src/megolm/message.rs:58: replace MegolmMessage::mac -> [u8 ; Mac::TRUNCATED_LEN] with Default::default() ... NOT CAUGHT in 4.356s
    src/olm/session/message_key.rs:40: replace <impl Drop for RemoteMessageKey>::drop with () ... NOT CAUGHT in 4.240s
    src/types/mod.rs:31: replace <impl From for String>::from -> String with "xyzzy".into() ... NOT CAUGHT in 4.008s
    src/types/ed25519.rs:113: replace Ed25519SecretKey::to_base64 -> String with "xyzzy".into() ... NOT CAUGHT in 3.903s
    src/olm/account/fallback_keys.rs:48: replace FallbackKey::mark_as_published with () ... NOT CAUGHT in 3.929s
    src/megolm/message.rs:48: replace MegolmMessage::ciphertext -> &[u8] with Default::default() ... NOT CAUGHT in 4.259s
    src/types/curve25519.rs:132: replace Curve25519PublicKey::to_vec -> Vec<u8> with Default::default() ... NOT CAUGHT in 4.309s
    src/megolm/session_keys.rs:83: replace <impl Zeroize for ExportedSessionKey>::zeroize with () ... NOT CAUGHT in 4.291s
    src/olm/account/fallback_keys.rs:52: replace FallbackKey::published -> bool with false ... NOT CAUGHT in 4.010s
    src/olm/session/mod.rs:202: replace Session::has_received_message -> bool with false ... NOT CAUGHT in 4.159s
    src/olm/session/mod.rs:420: replace Session::from_libolm_pickle::<impl Drop for Pickle>::drop with () ... NOT CAUGHT in 4.347s
    src/megolm/session_keys.rs:90: replace <impl Drop for ExportedSessionKey>::drop with () ... NOT CAUGHT in 4.089s
    src/types/curve25519.rs:169: replace <impl Debug for Curve25519PublicKey>::fmt -> std::fmt::Result with Ok(Default::default()) ... NOT CAUGHT in 4.158s
    src/olm/session/chain_key.rs:70: replace RemoteChainKey::chain_index -> u64 with Default::default() ... TIMEOUT in 21.756s
    src/types/ed25519.rs:240: replace Ed25519PublicKey::verify -> Result<(), SignatureError> with Ok(Default::default()) ... NOT CAUGHT in 4.356s
    src/types/ed25519.rs:113: replace Ed25519SecretKey::to_base64 -> String with "".into() ... NOT CAUGHT in 4.009s
    src/sas.rs:383: replace EstablishedSas::verify_mac -> Result<(), SasError> with Ok(Default::default()) ... NOT CAUGHT in 4.366s
    src/types/mod.rs:37: replace KeyId::to_base64 -> String with "".into() ... NOT CAUGHT in 4.009s
    src/olm/messages/pre_key.rs:147: replace PreKeyMessage::wrap -> Self with Default::default() ... NOT CAUGHT in 4.124s
    src/olm/session/message_key.rs:71: replace MessageKey::ratchet_key -> RatchetPublicKey with Default::default() ... NOT CAUGHT in 4.174s
    src/olm/account/fallback_keys.rs:69: replace FallbackKeys::mark_as_published with () ... NOT CAUGHT in 4.406s
    
    opened by poljar 0
  • Many libolm unpickling structs have Debug implementations

    Many libolm unpickling structs have Debug implementations

    While the Debug implementations aren't really harmful since they can't be used, all the structs are private, we should remove them since we don't want to have any Debug implementations over private key material.

    opened by poljar 0
  • Interoperability with libolm

    Interoperability with libolm

    I am trying to use Megolm. Having one side running the (Outbound)GroupSession, and the other side the InboundGroupSession. Pretty straightforward I guess.

    On the outbound side I would like to use this crate, as it is native Rust. On the incoming side, I need to use libolm, or at least, I want to enable users to use libolm if they like.

    Now the problem seems to be that there are different "pickle" formats. And they don't work together very well. My original issue was that I cannot decode on the libolm side, as I get "BAD_SIGNATURE". While the same message gets decoded by this create just fine.

    So I tried some tests, trying to use olm-rs (which is a wrapper to libolm) in the process and see where the differences are. However, I can't import a session pickle created by this create into libolm. I also cannot create a GroupSession from a libolm pickle, only an InboundGroupSession, as the "from libolm" function doesn't exist GroupSession.

    All of this is a pretty frustration experience, and I guess it would be helpful to document what is expected to work, and what not.

    On top of that, I think there should be a way that both implementations can be used together. And if can't export a pickle to the libolm format from this crate, then at least I should be able to import an (Outbound) GroupSession from a libolm pickle.

    opened by ctron 4
  • Update ed25519-dalek to allow rust-analyzer to work properly

    Update ed25519-dalek to allow rust-analyzer to work properly

    From #3, this is currently blocked as-is.

    I'm converting that PR into an issue to track this problem, as ed25519-dalek has gone two years without a release, with some improvements on master branch that should be in a normal release.

    Original issue, which is now closed as fixed, but not in a release yet: https://github.com/dalek-cryptography/ed25519-dalek/issues/173

    Issue on their repo calling for a new release: https://github.com/dalek-cryptography/ed25519-dalek/issues/192


    Alternatively, the following could be added to .vscode/settings.json to fix this for everyone using vscode;

      "rust-analyzer.cargo.unsetTest": [
        "core",
        "ed25519-dalek"
      ],
    
    opened by ShadowJonathan 0
  • Replace `#[zeroize(drop)]` with `#[derive(ZeroizeOnDrop)]` when moving to `zeroize` 1.5.x

    Replace `#[zeroize(drop)]` with `#[derive(ZeroizeOnDrop)]` when moving to `zeroize` 1.5.x

    In zeroize 1.5.x, the #[zeroize(drop)] attribute was deprecated and replaced with ZeroizeOnDrop. We can't switch to newer zeroize versions due to dalek, but once we do, we should replace all uses of #[zeroize(drop)].

    opened by dkasak 0
Owner
matrix.org
A new basis for open, interoperable, decentralised real-time communication
matrix.org
An i386 operation system written in pure rust for fun and no profit.

OrustS An i386 operation system written in pure rust (for fun and no profit). This operation system is under active developing. Checklist implement a

M4tsuri 10 Aug 12, 2022
An mdBook single PDF generator using pure Rust and some Node.js

mdbook-compress An mdBook backend renderer to generate a single PDF file for a full book. There are other similar projects, but most rely on chrome in

nxe 44 Jan 20, 2023
High-order Virtual Machine (HVM) is a pure functional compile target that is lazy, non-garbage-collected and massively parallel

High-order Virtual Machine (HVM) High-order Virtual Machine (HVM) is a pure functional compile target that is lazy, non-garbage-collected and massivel

null 5.5k Jan 2, 2023
Highly experimental, pure-Rust big integer library

grou-num (Pronounced "groo", from the Chiac meaning "big") This package is a highly experimental, unstable big integer library. I would not recommend

Patrick Poitras 1 Dec 18, 2021
Pure-Rust DTLS

dustls, a pure-rust DTLS implementation A DTLSv1.2 implementation in Rust, reusing rustls for cryptographic primitives and most message payload format

Jonathan de Jong 10 Nov 28, 2022
Generic inventory system built in pure rust.

game_inventory A framework for generalizing inventory logic and abstracting it away from item data in your specific game. See more examples and specif

null 7 Jul 30, 2022
A pure-rust(with zero dependencies) fenwick tree, for the efficient computation of dynamic prefix sums.

indexset A pure-rust(with zero dependencies, no-std) fenwick tree, for the efficient computation of dynamic prefix sums. Background Did you ever have

Bruno Rucy Carneiro Alves de Lima 2 Jul 13, 2023
Rust implementation of Andrej Karpathy's micrograd for purposes of learning both ML and Rust.

micrograd_rs Rust implementation of Andrej Karpathy's micrograd for purposes of learning both ML and Rust. Main takeaways Basically the same takeaways

null 3 Oct 28, 2022
fast rust implementation of online nonnegative matrix factorization as laid out in the paper "detect and track latent factors with online nonnegative matrix factorization"

ONMF status: early work in progress. still figuring this out. code still somewhat messy. api still in flux. fast rust implementation of online nonnega

null 2 Apr 10, 2020
A fast lean and clean modern constraint programming solver implementation (in rust)

MaxiCP-rs This project aims at implementing a fast, and clean constraint programming solver with a focus on correctness, simplicity, maintainability a

Xavier Gillard 5 Dec 10, 2022
A Rust implementation of V8's ValueSerializer and ValueDeserializer

v8_valueserializer This module implements the V8 ValueSerializer and ValueDeserializer API in Rust. It can serialize and deserialize any value that ca

Deno 7 Nov 8, 2023
An implementation of a predicative polymorphic language with bidirectional type inference and algebraic data types

Vinilla Lang Vanilla is a pure functional programming language based on System F, a classic but powerful type system. Merits Simple as it is, Vanilla

Zehao Chen 73 Aug 4, 2022
A radix tree implementation for router, and provides CRUD operations.

radixtree A radix tree implementation for router, and provides CRUD operations. Radixtree is part of treemux, on top of which updates and removes are

Zhenwei Guo 2 Dec 19, 2022
Majestic Lisp book and implementation, in Brazillian Portuguese.

Majestic Lisp Criado e desenvolvido por Lucas S. Vieira <lucasvieira at protonmail dot com>. Seja bem-vindo(a) a Majestic Lisp, um dialeto de Lisp cuj

Lucas Vieira 3 Oct 26, 2022
Ray Tracing: The Next Week implementation in Rust

rttnw Ray Tracing: The Next Week implementation in Rust How to run Install Rust: Link here. Run project git clone https://github.com/luliic2/rttnw cd

null 20 Apr 26, 2022
Rust implementation of µKanren, a featherweight relational programming language.

µKanren-rs This is a Rust implementation of µKanren, a featherweight relational programming language. See the original Scheme implementation here for

Eric Zhang 99 Dec 8, 2022
A Rust implementation of generic prefix tree (trie) map with wildcard capture support

prefix_tree_map A Rust implementation of generic prefix tree (trie) map with wildcard capture support. Design Trie is a good data structure for storin

EAimTY 3 Dec 6, 2022
A modular implementation of timely dataflow in Rust

Timely Dataflow Timely dataflow is a low-latency cyclic dataflow computational model, introduced in the paper Naiad: a timely dataflow system. This pr

Timely Dataflow 2.7k Dec 30, 2022
An alternative broken buggy Nix implementation in Rust + Java (for evaluation)

An alternative broken buggy Nix implementation in Rust + Java (for evaluation)

Moritz Hedtke 1 Feb 12, 2022