Skip to content

Instantly share code, notes, and snippets.

@zarutian
Last active April 6, 2018 00:54
Show Gist options
  • Save zarutian/fb21d0a8c910ab255401 to your computer and use it in GitHub Desktop.
Save zarutian/fb21d0a8c910ab255401 to your computer and use it in GitHub Desktop.
CapTP using MessagePack wire encoding.
CapTP using MsgPack (v4.3.2)
(MsgPack see https://github.com/msgpack/msgpack/blob/master/spec.md )
letrc := msgpck_ext_0 ( msgpck_uint msgpck_any ) -- is same as <msgpck_any> but also adds the object to the ibid table
ibid := msgpck_ext_1 ( msgpck_uint ) -- looks up in the ibid table, if anything isnt found returns nil
messages := message [messages]
message := DeliverOnly | Deliver | GCExport | GCAnswer | Shutdown | Terminated
DeliverOnly := msgpck_ext_2 ( recipiant verb args namedArgs )
Deliver := msgpck_ext_3 ( answerPos rdr recipiant verb args namedArgs )
GCExport := msgpck_ext_4 ( exportPos wireDelta )
GCAnswer := msgpck_ext_5 ( answerPos )
Shutdown := msgpck_ext_6 ( recivedCount )
Terminated := msgpck_ext_7 ( problem )
recipiant := anyObj
verb := msgpck_UTF8_string
args := msgpck_array ( anyObj* )
namedArgs := msgpck_map ( anyPair* ) | elided
anyPair := anyObj anyObj
elided : basically means it is left out
anyObj := Export | Answer | Import | Question | newFarDesc |
newRemotePromiseDesc | newPromise3Desc | RemoteCall |
RemoteDelviery | LocatorUnumDesc | SturdyRef | msgpck_any |
ActiveCapCert | Macaroony | PostalRefACC | PostalRefM
Export := msgpck_ext_8 ( exportPos )
Answer := msgpck_ext_9 ( answerPos )
Import := msgpck_ext_10 ( importPos )
Question := msgpck_ext_11 ( questionPos )
newFarDesc := msgpck_ext_12 ( importPos SwissHash )
newRemotePromiseDesc := msgpck_ext_13 ( importPos rdrPos rdrBase )
newPromise3Desc := msgpck_ext_14 ( searchPath hostID nonce vine )
RemoteDeliver := msgpck_ext_15 ( recipiant verb args namedArgs )
RemoteCall := msgpck_ext_16 ( recipiant verb args namedArgs )
LocatorUnumDesc := msgpck_ext_17 ( )
SturdyRef := msgpck_ext_18 ( locator searchPath hostId swissNum expiry )
NonceLocator := msgpck_ext_8 ( <exportPos == 0> ) | msgpck_ext_9 ( <importPos == 0> )
exportPos := msgpck_uint -- speaker imports, listener exports (Speaker: "Hey listener, about your export #xxx...")
importPos := msgpck_uint -- speaker exports, listener imports (Speaker: "Hey listener, about my export #xxx...")
answerPos := msgpck_uint -- speaker assigns, listener follows
questionPos := msgpck_uint -- speaker follows, listener assigns
searchPath := msgpck_array( [searchPathItem [ searchPathItems ] ] )
searchPathItem := msgpck_string
searchPathItems := searchPathItem [ searchPathItems ]
hostId := VatID
vine := anyObj
rdr := anyObj
rdrPos := answerPos
rdrBase := swissBase
swissHash := crypto_hash(swissNum)
swissNum := crypto_hash(swissBase)
swissBase := random_bytestring
expiry := msgpck_ext26 (RFC3339 date as utf8/ASCII) |
msgpck_ext27 (TAI64 date as binary bytes) -- see https://cr.yp.to/libtai/tai64.html can be 8, 12 or 16 bytes
-- use another extenstion nrs for other cryptographic hashes
crypto_hash(item) := msgpck_ext19 (SHA256(item)) |
msgpck_ext24 (Blake2d_32(item)) |
msgpck_ext25 (Blake2d_64(item))
VatId := crypto_hash(<public key of that Vat>)
ActiveCapCert := msgPack_ext20 ( ACC_issuer ACC_function ACC_signature )
PostalRefACC := msgpck_ext21 ( )
Macaroony := msgpck_ext22 ( libmacaroon_format )
PostalRefRefM := msgpck_ext23 ( )
ACC_issuer := VatId | OpenPGP_public_key | OpenSSL_public_key
ACC_function := ACC_function_parameters ACC_function_body
ACC_function_parameters := ACC_function_parameter*
ACC_function_body : Thinking about restrecting these to computing class of primitive recursive functions.
ACC_signature : ACC_issuers signature of ACC_function
perhaps see SPKI on how to store signatures and public keys.
msgpck_any := msgpck_int | msgpck_bytestring | msgpck_UTF8_string | msgpck_bool |
msgpck_map ( msgpck_map_entry* ) | msgpck_array ( msgpck_any* ) | anyObj
msgpck_UTF8_string := msgpck_string
msgpck_map_entry := msgpck_any msgpck_any
libmacaroon_format := libmacaroon_record [...] # not base64 encoded
libmacaroon_record := libmacaroon_recordLength libmacaroon_recordUTF8string
libmacaroon_recordLength := libmacaroon_hexDigit * 4 # bigendian length of the following string
libmacaroon_hexDigit := "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "A" | "B" | "C" | "D" | "E" | "F"
libmacaroon_recordUTF8string := libmacaroon_identifier | libmacaroon_signature | libmacaroon_1stPartyCaveat |
libmacaroon_3rdPartyCaveat | libmacaroon_3rdPartyDischarge | macaroony_messages |
macaroony_MustByVatCaveat | macaroony_encrypted
macaroony_messages := "mrymsg " messages
libmacaroon_identifier := "identifier vatId:" hex(vatId) " swissHash:" hex(swissHash) # the corrisponding swissNum is then the starting HMAC key of the macaroon
Generally, the smallest possible msgpck representation is used for each datum.
Example 1:
(doesnt use ibids)
I = initiator, the vat that initiates the connection
S = servicer, the vat that recives that initation
the hexdecimals are the data sent on the wire (not though as hex but as bytes) the rest is just commentary
--- initatior establishes an VatTP to servicer
I:
c73803 Deliver message
01 answer position #1 (servicer is expected to answer and put it at this position in its answer table)
d5 redirector (rdr) is a newFarDesc
01 export position #1 (initator is exporting)
c0 no swissHash
d40800 recipiant is the nonceLocator at servicers end
ab 6c6f6f6b75705377697373 -- verb is "lookupSwiss"
92 args array
c72013 swissNum of "Calculator"
668b80455fdbae2f6816c7d0d542c0238d627b3da0454e14388bd429713590e1
c0 no vine
c71303 Deliver message
02 answer position #2
d5 redirector (rdr) is a newFarDesc
02 export position #2 (initator is exporting)
c0 no swissHash
d40901 recipiant is the answer #1 in servicers answers table
a8 6d756c7469706c79 verb is "multiply"
92 args array
02 the number 2
03 the number 3
c70f03 Deliver message
03 answer position #3
d5 redirector (rdr) is a newFarDesc
03 export position #3 (initator is exporting)
c0 no swissHash
d40901 recipiant is the answer #1 in servicers answers table
a4 706c7573 verb is "plus"
92 args array
04 the number 4
03 the number 3
c70f03 Deliver message
04 answer position #4
d5 redirector (rdr) is a newFarDesc
04 export position #4 (initator is exporting)
c0 no swissHash
d40901 recipiant is the answer #1 in servicers answers table
a8 6d756c7469706c79 verb is "multiply"
92 args array
d40902 answer #2
d40903 answer #3
(126 bytes in this packet/tcp_segment)
S:
c70e02 DeliverOnly
d40801 recipiant is initiators export #1
a3 72756e verb is "run"
91 args array
d40b01 the answer to initiators question #1
c70902 DeliverOnly
d40802 recipiant is initiators export #2
a3 72756e verb is "run"
91 args array
06 the number 6
c70902 DeliverOnly
d40803 recipiant is initators export #3
a3 72756e verb is "run"
91 args array
07 the number 7
c70c02 DeliverOnly
d40804 recipiant is initators export #4
a3 72756e verb is "run"
91 args array
2a the number 42
(50 bytes in this packet/tcp_segment)
Example 2:
(uses ibids)
I:
c7__03 Deliver message
01 answer position nr #1
d5 redirector, a new fardesc
42 export position nr #66
c0 no swissHash
d40800 recipiant is the nonceLocator at servicers end
c70d00 letrc
01 ibid location 1
ab 6c6f6f6b75705377697373 the verb "lookupSwiss"
# This file is now out of date, see instead https://github.com/zarutian/monte_stuff/blob/streamcap-use/serial/kits/msgpckKit.mt
# Monte syntax&semantics
def makeMsgunpacker (fount, drain) as DeepFrozen:
var buffer := [].diverge()
var k := [].asMap().diverge()
k['\x00'] = fn (byte):
buffer := buffer.slice(1, buffer.size() - 1)
drain <- receive(decodeU8bit(byte))
return
for (var i := 1; i <= 0x7f; i++)
k[i.asChar()] = k['\x00']
k['\x80'] := fn (byte):
# Fixmap
buffer := buffer.slice(1, buffer.size() - 1)
var pairn := decodeU8bit(byte.and(0x0f))
drain <- receive(makeMapMark(pairn))
return
for (var i := 0x81; i <= 0x8f; i++)
k[i.asChar()] = k['\x80']
k['\x90'] = fn (byte):
# Fixarray
buffer := buffer.slice(1, buffer.size() - 1)
var itemn := decodeU8bit(byte.and(0x0f))
drain <- receive(makeArrayMark(itemn))
return
for (var i := 0x91; i <= 0x9f; i++)
k[i.asChar()] := k['\x90']
k['\xa0'] := fn (byte)
# Fixstr
var size := buffer.size()
var length := decodeU8bit(byte.and(0x1f))
if (size < (1 + length))
return
var str := buffer.slice(1, length)
buffer := buffer.slice((1 + length), size - 1)
drain <- receive(makeStr(str))
return
for (var i := 0xa1; i <= 0xbf; i++)
k[i.asChar()] := k['\xa0']
k['\xc0'] = fn (_):
# Nil
buffer := buffer.slice(1, buffer.size() - 1)
drain <- receive(Nil)
return
k['\xc1'] = fn (_):
# never used
buffer := buffer.slice(1, buffer.size() - 1)
return
k['\xc2'] = fn (_):
# Boolean false
buffer := buffer.slice(1, buffer.size() - 1)
drain <- receive(false)
return
k['\xc3'] = fn(_):
# Boolean true
buffer := buffer.slice(1, buffer.size() - 1)
drain <- receive(true)
return
k['\xc4'] = fn (_):
# Bin 8
var size = buffer.size()
if (size < 2)
return
var length := decodeU8bit(buffer[1])
if (size < (2 + length))
return
var bin := buffer.slice(2, (2 + length - 1))
buffer := buffer.slice((2 + length), size - 1)
drain <- receive(makeBinary(bin))
return
k['\xc5'] = fn (_):
# Bin 16
var size = buffer.size()
if (size < 3)
return
var length := decodeU16bit(buffer.slice(1,2))
if (size < (3 + length))
return
var bin := buffer.slice(3, (3 + length - 1))
buffer := buffer.slice((3 + length), size - 1)
drain <- receive(makeBinary(bin))
return
k['\xc6'] = fn (_):
# Bin 32
var size = buffer.size()
if (size < 5)
return
var length := decodeU32bit(buffer.slice(1,4))
if (size < (5 + length))
return
var bin := buffer.slice(5, (5 + length - 1))
buffer := buffer.slice((5 + length), size - 1)
drain <- receive(makeBinary(bin))
return
k['\xc7'] = fn (_):
# Ext 8
var size = buffer.size()
if (size < 3)
return
var length := decodeU8bit(buffer[1])
var type := decodeI8bit(buffer[2])
if (size < (3 + length))
return
var ext := buffer.slice(3, (3 + length - 1))
buffer := buffer.slice((3 + length), size - 1)
drain <- receive(makeExt(type, ext))
return
k['\xc8'] = fn (_):
# Ext 16
var size = buffer.size()
if (size < 4)
return
var length := decodeU16bit(buffer.slice(1,2))
var type := decodeI8bit(buffer[3])
if (size < (4 + length))
return
var ext := buffer.slice(4, (4 + length - 1))
buffer := buffer.slice((4 + length), size - 1)
drain <- receive(makeExt(type, ext))
return
k['\xc9'] = fn (_):
# Ext 32
var size = buffer.size()
if (size < 6)
return
var length := decodeU32bit(buffer.slice(2, 5))
var type := decodeU8bit(buffer[6])
if (size < (7 + length))
return
var ext := buffer.slice(7, (7 + length - 1))
buffer := buffer.slice((7 + length), size - 1)
drain <- receive(makeExt(type, ext))
return
k['\xca'] := fn (_):
# Float, single
if (buffer.size() < 5)
return
var f := buffer.slice(1, 4)
buffer := buffer.slice(5, buffer.size() - 1)
drain <- receive(makeFloat(f))
return
k['\xcb'] := fn (_):
# Float, double
if (buffer.size() < 9)
return
var f := buffer.slice(1,8)
buffer := buffer.slice(9, buffer.size() - 1)
drain <- receive(makeFloat(f))
return
k['\xcc'] := fn (_):
# Uint 8
k['\xcd`] := fn (_):
# Uint 16
k['\xce'] := fn (_):
# Uint 32
k['\xcf'] := fn (_):
# Uint 64
return object unpacker:
to receive(byte):
buffer with= (byte)
k[buffer[0]](buffer[0])
local subgraphKit = {}
subgraphKit.makeBuilder = function (environ) -- near_guard on return values
local nextTemp = 0
local temps = {}
local Node = any_guard
local Root = any_guard
local subgraphBuilder = {}
subgraphBuilder.getNodeType = function ()
return near_guard(Node)
end
subgraphBuilder.getRootType = function ()
return near_guard(Node)
end
subgraphBuilder.buildRoot = function (root)
return Root(Node(root))
end
subgraphBuilder.buildLiteral = function (value)
return Node(value)
end
subgraphBuilder.buildImport = function (varName)
return Node(environ[string_guard(varName)])
end
subgraphBuilder.buildIbid = function (tempIndex)
return Node(temps[int_guard(tempIndex)])
end
subgraphBuilder.buildCall = function (reciver, verb, args)
reciver = Node(reciver)
verb = string_guard(verb)
args = array_guard(Node, args)
return Node(reciver[verb](args)) -- not quite sure about the args passing is correct
end
subgraphBuilder.buildPromise = function ()
local promIdx = nextTemp
nextTemp = nextTemp + 2
local prom, res = Reference.promise()
temps[promIdx] = prom
temps[promIdx + 1] = res
return int_guard(promIdx)
end
subgraphBuilder.buildDefrec = function (resIdx, rValue)
resIdx = int_guard(resIdx)
rValue = Node(rValue)
temps[resIdx].resolve(rValue)
return rValue
end
subgraphBuilder.buildDefine = subgraphBuilder.buildDefrec -- no non-cyclic cases optimization
return subgraphBuilder
end
local msgPckKit = {}
msgPckKit.makeBuilder = function (environ)
local Node = bytestring_guard
local Root = any_guard
local msgPckBuilder = {}
msgPckBuilder.getNodeType = function ()
return near_guard(Node)
end
msgPckBuilder.getRootType = function ()
return near_guard(Node)
end
msgPckBuilder.buildRoot = function (root)
return Root(Node(root))
end
msgPckBuilder.buildLiteral = function (value)
if nil_guard.matches(value) then
return Node("\xC0")
end
if bool_guard.matches(value) then
if value == false then
return Node("\xC2")
else
return Node("\xC3")
end
end
if int_guard.matches(value) then
if 0 <= value and value <= 127 then
-- do this with something like string format or some such
local lut = {}
lut[0] = "\x00"
lut[1] = "\x01"
lut[2] = "\x02"
lut[3] = "\x03"
lut[4] = "\x04"
return Node(lut[value])
else if -1 >= value and value >= -32 then
else if 128 <= value and value <= 255 then
else if 256 <= value and value <= 65535 then
else if 65536 <= value and value <= Math.pow(2,32)-1 then
else if Math.pow(2,32) <= value then
end
end
end
msgPckBuilder.buildImport = function (varName)
return Node(environ[string_guard(varName)])
end
msgPckBuilder.buildIbid = function (tempIndex)
return Node(int_guard(tempIndex))
end
msgPckBuilder.buildCall = function (reciver, verb, args)
reciver = Node(reciver)
verb = string_guard(verb)
args = array_guard(Node, args)
return Node(reciver[verb](args)) -- not quite sure about the args passing is correct
end
msgPckBuilder.buildPromise = function ()
local promIdx = nextTemp
nextTemp = nextTemp + 2
local prom, res = Reference.promise()
temps[promIdx] = prom
temps[promIdx + 1] = res
return int_guard(promIdx)
end
subgraphBuilder.buildDefrec = function (resIdx, rValue)
resIdx = int_guard(resIdx)
rValue = Node(rValue)
temps[resIdx].resolve(rValue)
return rValue
end
subgraphBuilder.buildDefine = subgraphBuilder.buildDefrec
return msgPckBuilder
end
local makeUnevaler = function (uncallerList, unenvironMap) -- near_guard on return value
local unevaler = {}
unevaler.recognize = function (root, builder)
local Root = builder.getRootType()
local Node = builder.getNodeType()
local uncallers = snapshot(uncallerList)
local unenviron = diverge(unenvironMap)
local generate
local genCall = function (reciver verb, args)
verb = string_guard(verb)
args = array_guard(any_guard, args)
local recExpr = generate(reciver)
local argExprs = {}
for arg in args do
table.insert(argExpr, generate(arg))
end
return Node(builder.buildCall(recExpr, verb, argExpr))
end
local genObject = function (obj)
if int_guard.matches(obj) then
return Node(builder.buildLiteral(obj))
end
if float64_guard.matches(obj) then
return Node(builder.buildLiteral(obj))
end
if char_guard.matches(obj) then
return Node(builder.buildLiteral(obj))
end
-- twine stuff?!?
for uncaller in uncallers do
local rec, verb, args = uncaller.optUncall(obj)
if rec ~= nil then
return genCall(rec, verb, args)
end
end
throw("Can not uneval " .. obj)
end
local genVarUse = function (varId)
varId = or_guard(varId, string_guard, int_guard)
if string_guard.matcheS(varId) then
return Node(builder.buildImport(varName))
else
return Node(builder.buildIbid(varName))
end
end
generate = function (object)
end
return Root( /* */ )
end
end
local makeSurgeon
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment