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§

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