//! A text-based data format for cryptographic network protocols. //! //! ``` //! use nettext::enc::*; //! use nettext::dec::*; //! use nettext::crypto::{self, Signer, Verifier}; //! //! let keypair = crypto::generate_keypair(); //! //! // Encode a fist object that represents a payload that will be hashed and signed //! let text1 = encode(list([ //! string("CALL"), //! string("myfunction"), //! dict([ //! ("a", string("hello")), //! ("b", string("world")), //! ("c", raw(b"{ a = 12, b = 42 }")), //! ]), //! keypair.public.term(), //! ])).unwrap(); //! eprintln!("{}", std::str::from_utf8(&text1).unwrap()); //! //! let hash = crypto::Blake2Sum::compute(&text1); //! let sign = keypair.sign(&text1); //! //! // Encode a second object that represents the signed and hashed payload //! let text2 = encode(dict([ //! ("hash", hash.term()), //! ("signature", sign.term()), //! ("payload", raw(&text1)), //! ])).unwrap(); //! eprintln!("{}", std::str::from_utf8(&text2).unwrap()); //! //! // Decode and check everything is fine //! let object1 = decode(&text2).unwrap(); //! let [hash, signature, payload] = object1.dict_of(["hash", "signature", "payload"], false).unwrap(); //! assert!(hash.b2sum().unwrap().verify(payload.raw()).is_ok()); //! assert_eq!(payload.raw(), text1); //! //! let object2 = decode(payload.raw()).unwrap(); //! //! let [verb, arg1, arg2, pubkey] = object2.list_of().unwrap(); //! let pubkey = pubkey.public_key().unwrap(); //! assert!(pubkey.verify(payload.raw(), &signature.signature().unwrap()).is_ok()); //! //! assert_eq!(verb.string().unwrap(), "CALL"); //! assert_eq!(arg1.string().unwrap(), "myfunction"); //! assert_eq!(pubkey, keypair.public); //! ``` //! //! The value of `text1` would be as follows: //! //! ```raw //! CALL myfunction { //! a = hello, //! b = world, //! c = { a = 12, b = 42 }, //! } gTjRjHtSX6OCwq3pdl9Bpg6M2h-2WkciKi0uNV8NQX0 //! ``` //! //! And the value of `text2` would be as follows: //! ```raw //! { //! hash = BEBZp98KF_d1rvBd5Ib8q1w_oGvrvIcKRXFv9kMB0ewOWH42OPd8qa0V_2ranV92z0mEdswftqvpAYebziTIew, //! payload = CALL myfunction { //! a = hello, //! b = world, //! c = { a = 12, b = 42 }, //! } gTjRjHtSX6OCwq3pdl9Bpg6M2h-2WkciKi0uNV8NQX0, //! signature = rAwIUTsCdoB_4eqo7r5e_J5ZHFaxHnXi99oNWi7h7y0mRfgt5u7-qXn7spIN1GcmDWYh4EPzoY34Br-sRxi0AA, //! } //! ``` pub mod crypto; pub mod dec; pub mod enc; // ---- syntactic elements of the data format ---- pub(crate) const DICT_OPEN: u8 = b'{'; pub(crate) const DICT_CLOSE: u8 = b'}'; pub(crate) const DICT_ASSIGN: u8 = b'='; pub(crate) const DICT_DELIM: u8 = b','; pub(crate) const STR_EXTRA_CHARS: &[u8] = b"._-*?"; pub(crate) fn is_string_char(c: u8) -> bool { c.is_ascii_alphanumeric() || STR_EXTRA_CHARS.contains(&c) } pub(crate) fn is_whitespace(c: u8) -> bool { c.is_ascii_whitespace() }