Crate nettext

source ·
Expand description

A text-based data format for cryptographic network protocols.

use nettext::enc::*;
use nettext::dec::*;
use nettext::crypto::*;

let final_payload = {
    let keypair = gen_signing_keypair();

    // Encode a fist object that represents a payload that will be hashed and signed
    let signed_payload = seq([
        string("CALL").unwrap(),
        string("myfunction").unwrap(),
        dict([
            ("a", string("hello").unwrap()),
            ("b", string("world").unwrap()),
            ("c", raw(b"{ a = 12; b = 42 }").unwrap()),
            ("d", bytes_split(&((0..128u8).collect::<Vec<_>>()))),
        ]).unwrap(),
        keypair.public_key().term().unwrap(),
    ]).unwrap().encode();
    eprintln!("{}", std::str::from_utf8(&signed_payload).unwrap());

    let hash = compute_hash(&signed_payload, None);
    let sign = compute_signature(&signed_payload[..], &keypair);

    // Encode a second object that represents the signed and hashed payload
    dict([
        ("hash", hash.term().unwrap()),
        ("signature", sign.term().unwrap()),
        ("payload", raw(&signed_payload).unwrap()),
    ]).unwrap().encode()
};
eprintln!("{}", std::str::from_utf8(&final_payload).unwrap());

// Decode and check everything is fine
let signed_object = decode(&final_payload).unwrap();
let [hash, signature, payload] = signed_object.dict_of(["hash", "signature", "payload"], false).unwrap();
let hash = hash.hash().unwrap();
let signature = signature.signature().unwrap();
let expected_hash = compute_hash(payload.raw(), None);
assert_eq!(hash, expected_hash);

let object2 = decode(payload.raw()).unwrap();

let [verb, arg1, arg2, pubkey] = object2.seq_of().unwrap();
let pubkey = pubkey.public_key().unwrap();
assert!(verify_signature(&signature, payload.raw(), &pubkey));

assert_eq!(verb.string().unwrap(), "CALL");
assert_eq!(arg1.string().unwrap(), "myfunction");

The value of signed_payload would be as follows:

CALL myfunction {
    a = hello;
    b = world;
    c = { a = 12; b = 42 };
    d = AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4v
      MDEyMzQ1Njc4OTo7PD0-P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5f
      YGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn8;
  } pk.ed25519:inYgWFyL_BzZTsXNKp71r2aVct_3Izi_bkerbzOiz94

And the value of final_payload would be as follows:

{
  hash = h.b2:B1AnRocS90DmqxynGyvvBNuh-brucNO7-5hrsGplJr0;
  payload = CALL myfunction {
    a = hello;
    b = world;
    c = { a = 12; b = 42 };
    d = AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4v
      MDEyMzQ1Njc4OTo7PD0-P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5f
      YGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn8;
  } pk.ed25519:inYgWFyL_BzZTsXNKp71r2aVct_3Izi_bkerbzOiz94;
  signature = sig.ed25519:LvLC1gHxNxUH44HHQRO-zWtLM4WyXhiYLFr94qTdI311Wa-kmgZsaWqSWe3jcjkS4PnsWSNt5apgbhR68cWWCg;
}

Note that the value of text1 is embedded as-is inside text2. This is what allows us to check the hash and the signature: the raw representation of the term hasn’t changed.

Modules

  • Helpers to use cryptographic data types in nettext
  • Functions to decode nettext and helpers to map it to data structures
  • Functions to generate nettext representations of data structures
  • Serde serialization and deserialization for nettext