mirror of
https://github.com/urbit/shrub.git
synced 2024-11-24 13:06:09 +03:00
ames: flat packet format
This commit is contained in:
parent
a7f11df506
commit
c7b8ffbf4e
@ -105,7 +105,9 @@
|
||||
rot=`?`%.n :: routing attempts
|
||||
==
|
||||
=>
|
||||
~% %ames ..is ~
|
||||
|%
|
||||
+| %helpers
|
||||
:: +trace: print if .verb is set and we're tracking .ship
|
||||
::
|
||||
++ trace
|
||||
@ -117,22 +119,373 @@
|
||||
~+ |(=(~ ships) (~(has in ships) ship))
|
||||
same
|
||||
(slog leaf/"ames: {(scow %p ship)}: {(print)}" ~)
|
||||
--
|
||||
=>
|
||||
~% %ames-generics ..is ~
|
||||
|%
|
||||
:: +qos-update-text: notice text for if connection state changes
|
||||
::
|
||||
++ qos-update-text
|
||||
|= [=ship old=qos new=qos]
|
||||
^- (unit tape)
|
||||
::
|
||||
?+ [-.old -.new] ~
|
||||
[%unborn %live] `"; {(scow %p ship)} is your neighbor"
|
||||
[%dead %live] `"; {(scow %p ship)} is ok"
|
||||
[%live %dead] `"; {(scow %p ship)} not responding still trying"
|
||||
[%unborn %dead] `"; {(scow %p ship)} not responding still trying"
|
||||
[%live %unborn] `"; {(scow %p ship)} has sunk"
|
||||
[%dead %unborn] `"; {(scow %p ship)} has sunk"
|
||||
==
|
||||
:: +lte-packets: yes if a is before b
|
||||
::
|
||||
++ lte-packets
|
||||
|= [a=live-packet-key b=live-packet-key]
|
||||
^- ?
|
||||
::
|
||||
?: (lth message-num.a message-num.b)
|
||||
%.y
|
||||
?: (gth message-num.a message-num.b)
|
||||
%.n
|
||||
(lte fragment-num.a fragment-num.b)
|
||||
:: +split-message: split message into kilobyte-sized fragments
|
||||
::
|
||||
:: We don't literally split it here since that would allocate many
|
||||
:: large atoms with no structural sharing. Instead, each
|
||||
:: static-fragment has the entire message and a counter. In
|
||||
:: +encrypt, we interpret this to get the actual fragment.
|
||||
::
|
||||
++ split-message
|
||||
~/ %split-message
|
||||
|= [=message-num =message-blob]
|
||||
^- (list static-fragment)
|
||||
::
|
||||
=/ num-fragments=fragment-num (met 13 message-blob)
|
||||
=| counter=@
|
||||
::
|
||||
|- ^- (list static-fragment)
|
||||
?: (gte counter num-fragments)
|
||||
~
|
||||
::
|
||||
:- [message-num num-fragments counter `@`message-blob]
|
||||
$(counter +(counter))
|
||||
:: +assemble-fragments: concatenate fragments into a $message
|
||||
::
|
||||
++ assemble-fragments
|
||||
~/ %assemble-fragments
|
||||
|= [num-fragments=fragment-num fragments=(map fragment-num fragment)]
|
||||
^- *
|
||||
::
|
||||
=| sorted=(list fragment)
|
||||
=. sorted
|
||||
=/ index=fragment-num 0
|
||||
|- ^+ sorted
|
||||
?: =(index num-fragments)
|
||||
sorted
|
||||
$(index +(index), sorted [(~(got by fragments) index) sorted])
|
||||
::
|
||||
%- cue
|
||||
%+ can 13
|
||||
%+ turn (flop sorted)
|
||||
|=(a=@ [1 a])
|
||||
:: +bind-duct: find or make new $bone for .duct in .ossuary
|
||||
::
|
||||
++ bind-duct
|
||||
|= [=ossuary =duct]
|
||||
^+ [next-bone.ossuary ossuary]
|
||||
::
|
||||
?^ existing=(~(get by by-duct.ossuary) duct)
|
||||
[u.existing ossuary]
|
||||
::
|
||||
:- next-bone.ossuary
|
||||
:+ (add 4 next-bone.ossuary)
|
||||
(~(put by by-duct.ossuary) duct next-bone.ossuary)
|
||||
(~(put by by-bone.ossuary) next-bone.ossuary duct)
|
||||
:: +make-bone-wire: encode ship and bone in wire for sending to vane
|
||||
::
|
||||
++ make-bone-wire
|
||||
|= [her=ship =bone]
|
||||
^- wire
|
||||
::
|
||||
/bone/(scot %p her)/(scot %ud bone)
|
||||
:: +parse-bone-wire: decode ship and bone from wire from local vane
|
||||
::
|
||||
++ parse-bone-wire
|
||||
|= =wire
|
||||
^- [her=ship =bone]
|
||||
::
|
||||
~| %ames-wire-bone^wire
|
||||
?> ?=([%bone @ @ ~] wire)
|
||||
[`@p`(slav %p i.t.wire) `@ud`(slav %ud i.t.t.wire)]
|
||||
:: +make-pump-timer-wire: construct wire for |packet-pump timer
|
||||
::
|
||||
++ make-pump-timer-wire
|
||||
|= [her=ship =bone]
|
||||
^- wire
|
||||
/pump/(scot %p her)/(scot %ud bone)
|
||||
:: +parse-pump-timer-wire: parse .her and .bone from |packet-pump wire
|
||||
::
|
||||
++ parse-pump-timer-wire
|
||||
|= =wire
|
||||
^- (unit [her=ship =bone])
|
||||
::
|
||||
~| %ames-wire-timer^wire
|
||||
?. ?=([%pump @ @ ~] wire)
|
||||
~
|
||||
?~ ship=`(unit @p)`(slaw %p i.t.wire)
|
||||
~
|
||||
?~ bone=`(unit @ud)`(slaw %ud i.t.t.wire)
|
||||
~
|
||||
`[u.ship u.bone]
|
||||
:: +derive-symmetric-key: $symmetric-key from $private-key and $public-key
|
||||
::
|
||||
:: Assumes keys have a tag on them like the result of the |ex:crub core.
|
||||
::
|
||||
++ derive-symmetric-key
|
||||
~/ %derive-symmetric-key
|
||||
|= [=public-key =private-key]
|
||||
^- symmetric-key
|
||||
::
|
||||
?> =('b' (end 3 1 public-key))
|
||||
=. public-key (rsh 8 1 (rsh 3 1 public-key))
|
||||
::
|
||||
?> =('B' (end 3 1 private-key))
|
||||
=. private-key (rsh 8 1 (rsh 3 1 private-key))
|
||||
::
|
||||
`@`(shar:ed:crypto public-key private-key)
|
||||
:: +encode-packet: serialize a packet into a bytestream
|
||||
::
|
||||
++ encode-packet
|
||||
~/ %encode-packet
|
||||
|= packet
|
||||
^- blob
|
||||
::
|
||||
=/ sndr-meta (encode-ship-metadata sndr)
|
||||
=/ rcvr-meta (encode-ship-metadata rcvr)
|
||||
::
|
||||
=/ body=@
|
||||
;: mix
|
||||
sndr-tick
|
||||
(lsh 2 1 rcvr-tick)
|
||||
(lsh 3 1 sndr)
|
||||
(lsh 3 +(size.sndr-meta) rcvr)
|
||||
(lsh 3 +((add size.sndr-meta size.rcvr-meta)) content)
|
||||
==
|
||||
=/ checksum (end 0 20 (mug body))
|
||||
=? body ?=(^ origin) (mix u.origin (lsh 3 6 body))
|
||||
::
|
||||
=/ header=@
|
||||
%+ can 0
|
||||
:~ [3 reserved=0]
|
||||
[1 is-ames=&]
|
||||
[3 protocol-version]
|
||||
[2 rank.sndr-meta]
|
||||
[2 rank.rcvr-meta]
|
||||
[20 checksum]
|
||||
[1 relayed=.?(origin)]
|
||||
==
|
||||
(mix header (lsh 5 1 body))
|
||||
:: +decode-packet: deserialize packet from bytestream or crash
|
||||
::
|
||||
++ decode-packet
|
||||
~/ %decode-packet
|
||||
|= =blob
|
||||
^- packet
|
||||
~| %decode-packet-fail
|
||||
:: first 32 (2^5) bits are header; the rest is body
|
||||
::
|
||||
=/ header (end 5 1 blob)
|
||||
=/ body (rsh 5 1 blob)
|
||||
:: read header; first three bits are reserved
|
||||
::
|
||||
=/ is-ames (cut 0 [3 1] header)
|
||||
?. =(& is-ames)
|
||||
~| %ames-not-ames !!
|
||||
::
|
||||
=/ version (cut 0 [4 3] header)
|
||||
?. =(protocol-version version)
|
||||
~| ames-protocol-version+version !!
|
||||
::
|
||||
=/ sndr-size (decode-ship-size (cut 0 [7 2] header))
|
||||
=/ rcvr-size (decode-ship-size (cut 0 [9 2] header))
|
||||
=/ checksum (cut 0 [11 20] header)
|
||||
=/ relayed (cut 0 [31 1] header)
|
||||
:: origin, if present, is 6 octets long, at the end of the body
|
||||
::
|
||||
=^ origin=(unit @) body
|
||||
?: =(| relayed)
|
||||
[~ body]
|
||||
=/ len (sub (met 3 body) 6)
|
||||
[`(end 3 6 body) (rsh 3 6 body)]
|
||||
:: .checksum does not apply to the origin
|
||||
::
|
||||
?. =(checksum (end 0 20 (mug body)))
|
||||
~| %ames-checksum !!
|
||||
:: read fixed-length sndr and rcvr life data from body
|
||||
::
|
||||
:: These represent the last four bits of the sender and receiver
|
||||
:: life fields, to be used for quick dropping of honest packets to
|
||||
:: or from the wrong life.
|
||||
::
|
||||
=/ sndr-tick (cut 0 [0 4] body)
|
||||
=/ rcvr-tick (cut 0 [4 4] body)
|
||||
:: read variable-length .sndr and .rcvr addresses
|
||||
::
|
||||
=/ off 1
|
||||
=^ sndr off [(cut 3 [off sndr-size] body) (add off sndr-size)]
|
||||
?. (is-valid-rank sndr sndr-size)
|
||||
~| ames-sender-impostor+[sndr sndr-size] !!
|
||||
::
|
||||
=^ rcvr off [(cut 3 [off rcvr-size] body) (add off rcvr-size)]
|
||||
?. (is-valid-rank rcvr rcvr-size)
|
||||
~| ames-receiver-impostor+[rcvr rcvr-size] !!
|
||||
:: read variable-length .content from the rest of .body
|
||||
::
|
||||
=/ content (cut 3 [off (sub (met 3 body) off)] body)
|
||||
[[sndr rcvr] sndr-tick rcvr-tick origin content]
|
||||
:: +is-valid-rank: does .ship match its stated .size?
|
||||
::
|
||||
++ is-valid-rank
|
||||
~/ %is-valid-rank
|
||||
|= [=ship size=@ubC]
|
||||
^- ?
|
||||
.= size
|
||||
?- (clan:title ship)
|
||||
%czar 2
|
||||
%king 2
|
||||
%duke 4
|
||||
%earl 8
|
||||
%pawn 16
|
||||
==
|
||||
:: +encode-open-packet: convert $open-packet attestation to $packet
|
||||
::
|
||||
++ encode-open-packet
|
||||
~/ %encode-open-packet
|
||||
|= [pac=open-packet =acru:ames]
|
||||
^- packet
|
||||
:* [sndr rcvr]:pac
|
||||
(mod sndr-life.pac 16)
|
||||
(mod rcvr-life.pac 16)
|
||||
origin=~
|
||||
content=`@`(sign:as:acru (jam pac))
|
||||
==
|
||||
:: +decode-open-packet: decode comet attestation into an $open-packet
|
||||
::
|
||||
++ decode-open-packet
|
||||
~/ %decode-open-packet
|
||||
|= [=packet our=ship our-life=@]
|
||||
^- open-packet
|
||||
:: deserialize and type-check packet contents
|
||||
::
|
||||
=+ ;; [signature=@ signed=@] (cue content.packet)
|
||||
=+ ;; =open-packet (cue signed)
|
||||
:: assert .our and .her and lives match
|
||||
::
|
||||
?> .= sndr.open-packet sndr.packet
|
||||
?> .= rcvr.open-packet our
|
||||
?> .= sndr-life.open-packet 1
|
||||
?> .= rcvr-life.open-packet our-life
|
||||
:: only a star can sponsor a comet
|
||||
::
|
||||
?> =(%king (clan:title (^sein:title sndr.packet)))
|
||||
:: comet public-key must hash to its @p address
|
||||
::
|
||||
?> =(sndr.packet fig:ex:(com:nu:crub:crypto public-key.open-packet))
|
||||
:: verify signature
|
||||
::
|
||||
:: Logic duplicates +com:nu:crub:crypto and +sure:as:crub:crypto.
|
||||
::
|
||||
=/ key (end 8 1 (rsh 3 1 public-key.open-packet))
|
||||
?> (veri:ed:crypto signature signed key)
|
||||
open-packet
|
||||
:: +encode-shut-packet: encrypt and packetize a $shut-packet
|
||||
::
|
||||
++ encode-shut-packet
|
||||
~/ %encode-shut-packet
|
||||
|= $: =shut-packet
|
||||
=symmetric-key
|
||||
sndr=ship
|
||||
rcvr=ship
|
||||
sndr-life=@
|
||||
rcvr-life=@
|
||||
==
|
||||
^- packet
|
||||
::
|
||||
=? meat.shut-packet
|
||||
?& ?=(%& -.meat.shut-packet)
|
||||
(gth (met 13 fragment.p.meat.shut-packet) 1)
|
||||
==
|
||||
%_ meat.shut-packet
|
||||
fragment.p
|
||||
(cut 13 [[fragment-num 1] fragment]:p.meat.shut-packet)
|
||||
==
|
||||
::
|
||||
=/ vec ~[sndr rcvr sndr-life rcvr-life]
|
||||
=/ [siv=@uxH len=@ cyf=@ux]
|
||||
(~(en sivc:aes:crypto (shaz symmetric-key) vec) (jam shut-packet))
|
||||
=/ content :(mix siv (lsh 7 1 len) (lsh 3 18 cyf))
|
||||
[[sndr rcvr] (mod sndr-life 16) (mod rcvr-life 16) origin=~ content]
|
||||
:: +decode-shut-packet: decrypt a $shut-packet from a $packet
|
||||
::
|
||||
++ decode-shut-packet
|
||||
~/ %decode-shut-packet
|
||||
|= [=packet =symmetric-key sndr-life=@ rcvr-life=@]
|
||||
^- shut-packet
|
||||
?. =(sndr-tick.packet (mod sndr-life 16))
|
||||
~| ames-sndr-tick+sndr-tick.packet !!
|
||||
?. =(rcvr-tick.packet (mod rcvr-life 16))
|
||||
~| ames-rcvr-tick+rcvr-tick.packet !!
|
||||
=/ siv (end 7 1 content.packet)
|
||||
=/ len (end 4 1 (rsh 7 1 content.packet))
|
||||
=/ cyf (rsh 3 18 content.packet)
|
||||
~| ames-decrypt+[[sndr rcvr origin]:packet len siv]
|
||||
=/ vec ~[sndr.packet rcvr.packet sndr-life rcvr-life]
|
||||
;; shut-packet %- cue %- need
|
||||
(~(de sivc:aes:crypto (shaz symmetric-key) vec) siv len cyf)
|
||||
:: +decode-ship-size: decode a 2-bit ship type specifier into a byte width
|
||||
::
|
||||
:: Type 0: galaxy or star -- 2 bytes
|
||||
:: Type 1: planet -- 4 bytes
|
||||
:: Type 2: moon -- 8 bytes
|
||||
:: Type 3: comet -- 16 bytes
|
||||
::
|
||||
++ decode-ship-size
|
||||
~/ %decode-ship-size
|
||||
|= rank=@ubC
|
||||
^- @
|
||||
::
|
||||
?+ rank !!
|
||||
%0b0 2
|
||||
%0b1 4
|
||||
%0b10 8
|
||||
%0b11 16
|
||||
==
|
||||
:: +encode-ship-metadata: produce size (in bytes) and address rank for .ship
|
||||
::
|
||||
:: 0: galaxy or star
|
||||
:: 1: planet
|
||||
:: 2: moon
|
||||
:: 3: comet
|
||||
::
|
||||
++ encode-ship-metadata
|
||||
~/ %encode-ship-metadata
|
||||
|= =ship
|
||||
^- [size=@ =rank]
|
||||
::
|
||||
=/ size=@ (met 3 ship)
|
||||
::
|
||||
?: (lte size 2) [2 %0b0]
|
||||
?: (lte size 4) [4 %0b1]
|
||||
?: (lte size 8) [8 %0b10]
|
||||
[16 %0b11]
|
||||
+| %atomics
|
||||
::
|
||||
+$ private-key @uwprivatekey
|
||||
+$ signature @uwsignature
|
||||
:: $rank: which kind of ship address, by length
|
||||
::
|
||||
:: 0: galaxy or star -- 2 bytes
|
||||
:: 1: planet -- 4 bytes
|
||||
:: 2: moon -- 8 bytes
|
||||
:: 3: comet -- 16 bytes
|
||||
:: 0b0: galaxy or star -- 2 bytes
|
||||
:: 0b1: planet -- 4 bytes
|
||||
:: 0b10: moon -- 8 bytes
|
||||
:: 0b11: comet -- 16 bytes
|
||||
::
|
||||
+$ rank ?(%0 %1 %2 %3)
|
||||
+$ rank ?(%0b0 %0b1 %0b10 %0b11)
|
||||
::
|
||||
+| %kinetics
|
||||
:: $channel: combined sender and receiver identifying data
|
||||
@ -165,7 +518,13 @@
|
||||
:: address. Routes are opaque to Arvo and only have meaning in the
|
||||
:: interpreter. This enforces that Ames is transport-agnostic.
|
||||
::
|
||||
+$ packet [dyad encrypted=? origin=(unit lane) content=*]
|
||||
+$ packet
|
||||
$: dyad
|
||||
sndr-tick=@ubC
|
||||
rcvr-tick=@ubC
|
||||
origin=(unit @uxaddress)
|
||||
content=@uxcontent
|
||||
==
|
||||
:: $open-packet: unencrypted packet payload, for comet self-attestation
|
||||
::
|
||||
:: This data structure gets signed and jammed to form the .contents
|
||||
@ -181,9 +540,7 @@
|
||||
:: $shut-packet: encrypted packet payload
|
||||
::
|
||||
+$ shut-packet
|
||||
$: =sndr=life
|
||||
=rcvr=life
|
||||
=bone
|
||||
$: =bone
|
||||
=message-num
|
||||
meat=(each fragment-meat ack-meat)
|
||||
==
|
||||
@ -691,14 +1048,16 @@
|
||||
``noun+!>(!>(res))
|
||||
==
|
||||
--
|
||||
:: helpers
|
||||
:: |per-event: inner event-handling core
|
||||
::
|
||||
~% %ames-helpers +>+ ~
|
||||
~% %per-event ..decode-packet ~
|
||||
|%
|
||||
++ per-event
|
||||
=| moves=(list move)
|
||||
~% %event-gate ..per-event ~
|
||||
|= [[our=ship now=@da eny=@ scry-gate=sley] =duct =ames-state]
|
||||
=* veb veb.bug.ames-state
|
||||
~% %event-core ..$ ~
|
||||
|%
|
||||
++ event-core .
|
||||
++ abet [(flop moves) ames-state]
|
||||
@ -848,20 +1207,14 @@
|
||||
=/ =channel [[our ship] now channel-state -.peer-state]
|
||||
abet:on-jilt:(make-peer-core peer-state channel)
|
||||
:: +on-hear: handle raw packet receipt
|
||||
::
|
||||
++ on-hear
|
||||
|= [=lane =blob]
|
||||
^+ event-core
|
||||
(on-hear-packet lane (decode-packet blob) ok=%.y)
|
||||
:: +on-hole: handle packet crash notification
|
||||
::
|
||||
++ on-hole
|
||||
|= [=lane =blob]
|
||||
^+ event-core
|
||||
(on-hear-packet lane (decode-packet blob) ok=%.n)
|
||||
++ on-hear |=([l=lane b=blob] (on-hear-packet l (decode-packet b) ok=&))
|
||||
++ on-hole |=([l=lane b=blob] (on-hear-packet l (decode-packet b) ok=|))
|
||||
:: +on-hear-packet: handle mildly processed packet receipt
|
||||
::
|
||||
++ on-hear-packet
|
||||
~/ %on-hear-packet
|
||||
|= [=lane =packet ok=?]
|
||||
^+ event-core
|
||||
::
|
||||
@ -873,9 +1226,11 @@
|
||||
?. =(our rcvr.packet)
|
||||
on-hear-forward
|
||||
::
|
||||
?: encrypted.packet
|
||||
on-hear-shut
|
||||
on-hear-open
|
||||
?: ?& ?=(%pawn (clan:title sndr.packet))
|
||||
!(~(has by peers.ames-state) sndr.packet)
|
||||
==
|
||||
on-hear-open
|
||||
on-hear-shut
|
||||
:: +on-hear-forward: maybe forward a packet to someone else
|
||||
::
|
||||
:: Note that this performs all forwarding requests without
|
||||
@ -883,18 +1238,27 @@
|
||||
:: provided by Vere.
|
||||
::
|
||||
++ on-hear-forward
|
||||
~/ %on-hear-forward
|
||||
|= [=lane =packet ok=?]
|
||||
^+ event-core
|
||||
%- %^ trace for.veb sndr.packet
|
||||
|.("forward: {<sndr.packet>} -> {<rcvr.packet>}")
|
||||
:: set .origin.packet if it doesn't already have one, re-encode, and send
|
||||
::
|
||||
=? origin.packet ?=(~ origin.packet) `lane
|
||||
=? origin.packet
|
||||
&(?=(~ origin.packet) !=(%czar (clan:title sndr.packet)))
|
||||
?: ?=(%& -.lane)
|
||||
~
|
||||
?. (lte (met 3 p.lane) 6)
|
||||
~| ames-lane-size+p.lane !!
|
||||
`p.lane
|
||||
::
|
||||
=/ =blob (encode-packet packet)
|
||||
(send-blob & rcvr.packet blob)
|
||||
:: +on-hear-open: handle receipt of plaintext comet self-attestation
|
||||
::
|
||||
++ on-hear-open
|
||||
~/ %on-hear-open
|
||||
|= [=lane =packet ok=?]
|
||||
^+ event-core
|
||||
:: assert the comet can't pretend to be a moon or other address
|
||||
@ -905,29 +1269,8 @@
|
||||
=/ ship-state (~(get by peers.ames-state) sndr.packet)
|
||||
?: ?=([~ %known *] ship-state)
|
||||
event-core
|
||||
:: deserialize and type-check packet contents
|
||||
::
|
||||
?> ?=(@ content.packet)
|
||||
=+ ;; [signature=@ signed=@] (cue content.packet)
|
||||
=+ ;; =open-packet (cue signed)
|
||||
:: assert .our and .her and lives match
|
||||
::
|
||||
?> .= sndr.open-packet sndr.packet
|
||||
?> .= rcvr.open-packet our
|
||||
?> .= sndr-life.open-packet 1
|
||||
?> .= rcvr-life.open-packet life.ames-state
|
||||
:: only a star can sponsor a comet
|
||||
::
|
||||
?> =(%king (clan:title (^sein:title sndr.packet)))
|
||||
:: comet public-key must hash to its @p address
|
||||
::
|
||||
?> =(sndr.packet fig:ex:(com:nu:crub:crypto public-key.open-packet))
|
||||
:: verify signature
|
||||
::
|
||||
:: Logic duplicates +com:nu:crub:crypto and +sure:as:crub:crypto.
|
||||
::
|
||||
=/ key (end 8 1 (rsh 3 1 public-key.open-packet))
|
||||
?> (veri:ed:crypto signature signed key)
|
||||
=/ =open-packet (decode-open-packet packet our life.ames-state)
|
||||
:: store comet as peer in our state
|
||||
::
|
||||
=. peers.ames-state
|
||||
@ -952,12 +1295,9 @@
|
||||
:: +on-hear-shut: handle receipt of encrypted packet
|
||||
::
|
||||
++ on-hear-shut
|
||||
~/ %on-hear-shut
|
||||
|= [=lane =packet ok=?]
|
||||
^+ event-core
|
||||
:: encrypted packet content must be an encrypted atom
|
||||
::
|
||||
?> ?=(@ content.packet)
|
||||
::
|
||||
=/ sndr-state (~(get by peers.ames-state) sndr.packet)
|
||||
:: if we don't know them, maybe enqueue a jael %public-keys request
|
||||
::
|
||||
@ -977,19 +1317,11 @@
|
||||
=/ =peer-state +.u.sndr-state
|
||||
=/ =channel [[our sndr.packet] now channel-state -.peer-state]
|
||||
~| %ames-crash-on-packet-from^her.channel
|
||||
=/ =shut-packet (decrypt symmetric-key.channel content.packet)
|
||||
:: ward against replay attacks
|
||||
::
|
||||
:: We only accept packets from a ship at their known life, and to
|
||||
:: us at our current life.
|
||||
::
|
||||
~| our-life=[expected=our-life.channel got=rcvr-life.shut-packet]
|
||||
~| her-life=[expected=her-life.channel got=sndr-life.shut-packet]
|
||||
?> =(sndr-life.shut-packet her-life.channel)
|
||||
?> =(rcvr-life.shut-packet our-life.channel)
|
||||
=/ =shut-packet
|
||||
(decode-shut-packet packet [symmetric-key her-life our-life]:channel)
|
||||
:: non-galaxy: update route with heard lane or forwarded lane
|
||||
::
|
||||
=? route.peer-state !=(%czar (clan:title her.channel))
|
||||
=? route.peer-state !=(%czar (clan:title her.channel))
|
||||
:: if new packet is direct, use that. otherwise, if the new new
|
||||
:: and old lanes are indirect, use the new one. if the new lane
|
||||
:: is indirect but the old lane is direct, then if the lanes are
|
||||
@ -1012,10 +1344,10 @@
|
||||
?: ?=(~ origin.packet)
|
||||
`[direct=%.y lane]
|
||||
?: ?=([~ %& *] route.peer-state)
|
||||
?: =(lane.u.route.peer-state u.origin.packet)
|
||||
?: =(lane.u.route.peer-state |+u.origin.packet)
|
||||
route.peer-state
|
||||
`[direct=%.n u.origin.packet]
|
||||
`[direct=%.n u.origin.packet]
|
||||
`[direct=%.n |+u.origin.packet]
|
||||
`[direct=%.n |+u.origin.packet]
|
||||
:: perform peer-specific handling of packet
|
||||
::
|
||||
=/ peer-core (make-peer-core peer-state channel)
|
||||
@ -1397,6 +1729,7 @@
|
||||
:: request the information from Jael if we haven't already.
|
||||
::
|
||||
++ send-blob
|
||||
~/ %send-blob
|
||||
|= [for=? =ship =blob]
|
||||
::
|
||||
=/ final-ship ship
|
||||
@ -1461,19 +1794,15 @@
|
||||
++ attestation-packet
|
||||
|= [her=ship =her=life]
|
||||
^- blob
|
||||
::
|
||||
=/ =open-packet
|
||||
:* ^= public-key pub:ex:crypto-core.ames-state
|
||||
^= sndr our
|
||||
^= sndr-life life.ames-state
|
||||
^= rcvr her
|
||||
^= rcvr-life her-life
|
||||
==
|
||||
::
|
||||
=/ signed=@ (sign:as:crypto-core.ames-state (jam open-packet))
|
||||
=/ =packet [[our her] encrypted=%.n origin=~ signed]
|
||||
::
|
||||
(encode-packet packet)
|
||||
%- encode-packet
|
||||
%- encode-open-packet
|
||||
:_ crypto-core.ames-state
|
||||
:* ^= public-key pub:ex:crypto-core.ames-state
|
||||
^= sndr our
|
||||
^= sndr-life life.ames-state
|
||||
^= rcvr her
|
||||
^= rcvr-life her-life
|
||||
==
|
||||
:: +get-peer-state: lookup .her state or ~
|
||||
::
|
||||
++ get-peer-state
|
||||
@ -1732,13 +2061,15 @@
|
||||
:: kind of flow this is (forward/backward), so flip the bit
|
||||
:: here.
|
||||
::
|
||||
=. bone.shut-packet (mix 1 bone.shut-packet)
|
||||
::
|
||||
=/ content (encrypt symmetric-key.channel shut-packet)
|
||||
=/ =packet [[our her.channel] encrypted=%.y origin=~ content]
|
||||
=/ =blob (encode-packet packet)
|
||||
::
|
||||
=. event-core (send-blob | her.channel blob)
|
||||
=. event-core
|
||||
%^ send-blob | her.channel
|
||||
%- encode-packet
|
||||
%: encode-shut-packet
|
||||
shut-packet(bone (mix 1 bone.shut-packet))
|
||||
symmetric-key.channel
|
||||
our her.channel
|
||||
our-life.channel her-life.channel
|
||||
==
|
||||
peer-core
|
||||
:: +got-duct: look up $duct by .bone, asserting already bound
|
||||
::
|
||||
@ -1796,17 +2127,7 @@
|
||||
:: +on-pump-send: emit message fragment requested by |message-pump
|
||||
::
|
||||
++ on-pump-send
|
||||
|= =static-fragment
|
||||
^+ peer-core
|
||||
:: encrypt and encode .static-fragment to .blob bitstream
|
||||
::
|
||||
%- send-shut-packet :*
|
||||
our-life.channel
|
||||
her-life.channel
|
||||
bone
|
||||
message-num.static-fragment
|
||||
%& +.static-fragment
|
||||
==
|
||||
|=(f=static-fragment (send-shut-packet bone [message-num %& +]:f))
|
||||
:: +on-pump-wait: relay |message-pump's set-timer request
|
||||
::
|
||||
++ on-pump-wait
|
||||
@ -1853,16 +2174,7 @@
|
||||
:: +on-sink-send: emit ack packet as requested by |message-sink
|
||||
::
|
||||
++ on-sink-send
|
||||
|= [=message-num =ack-meat]
|
||||
^+ peer-core
|
||||
::
|
||||
%- send-shut-packet :*
|
||||
our-life.channel
|
||||
her-life.channel
|
||||
bone
|
||||
message-num
|
||||
%| ack-meat
|
||||
==
|
||||
|=([num=message-num ack=ack-meat] (send-shut-packet bone num %| ack))
|
||||
:: +on-sink-memo: dispatch message received by |message-sink
|
||||
::
|
||||
:: odd bone: %plea request message
|
||||
@ -2783,259 +3095,4 @@
|
||||
::
|
||||
message-sink
|
||||
--
|
||||
:: +qos-update-text: notice text for if connection state changes
|
||||
::
|
||||
++ qos-update-text
|
||||
|= [=ship old=qos new=qos]
|
||||
^- (unit tape)
|
||||
::
|
||||
?+ [-.old -.new] ~
|
||||
[%unborn %live] `"; {(scow %p ship)} is your neighbor"
|
||||
[%dead %live] `"; {(scow %p ship)} is ok"
|
||||
[%live %dead] `"; {(scow %p ship)} not responding still trying"
|
||||
[%unborn %dead] `"; {(scow %p ship)} not responding still trying"
|
||||
[%live %unborn] `"; {(scow %p ship)} has sunk"
|
||||
[%dead %unborn] `"; {(scow %p ship)} has sunk"
|
||||
==
|
||||
:: +lte-packets: yes if a is before b
|
||||
::
|
||||
++ lte-packets
|
||||
|= [a=live-packet-key b=live-packet-key]
|
||||
^- ?
|
||||
::
|
||||
?: (lth message-num.a message-num.b)
|
||||
%.y
|
||||
?: (gth message-num.a message-num.b)
|
||||
%.n
|
||||
(lte fragment-num.a fragment-num.b)
|
||||
:: +split-message: split message into kilobyte-sized fragments
|
||||
::
|
||||
:: We don't literally split it here since that would allocate many
|
||||
:: large atoms with no structural sharing. Instead, each
|
||||
:: static-fragment has the entire message and a counter. In
|
||||
:: +encrypt, we interpret this to get the actual fragment.
|
||||
::
|
||||
++ split-message
|
||||
|= [=message-num =message-blob]
|
||||
^- (list static-fragment)
|
||||
::
|
||||
=/ num-fragments=fragment-num (met 13 message-blob)
|
||||
=| counter=@
|
||||
::
|
||||
|- ^- (list static-fragment)
|
||||
?: (gte counter num-fragments)
|
||||
~
|
||||
::
|
||||
:- [message-num num-fragments counter `@`message-blob]
|
||||
$(counter +(counter))
|
||||
:: +assemble-fragments: concatenate fragments into a $message
|
||||
::
|
||||
++ assemble-fragments
|
||||
|= [num-fragments=fragment-num fragments=(map fragment-num fragment)]
|
||||
^- *
|
||||
::
|
||||
=| sorted=(list fragment)
|
||||
=. sorted
|
||||
=/ index=fragment-num 0
|
||||
|- ^+ sorted
|
||||
?: =(index num-fragments)
|
||||
sorted
|
||||
$(index +(index), sorted [(~(got by fragments) index) sorted])
|
||||
::
|
||||
%- cue
|
||||
%+ can 13
|
||||
%+ turn (flop sorted)
|
||||
|=(a=@ [1 a])
|
||||
:: +bind-duct: find or make new $bone for .duct in .ossuary
|
||||
::
|
||||
++ bind-duct
|
||||
|= [=ossuary =duct]
|
||||
^+ [next-bone.ossuary ossuary]
|
||||
::
|
||||
?^ existing=(~(get by by-duct.ossuary) duct)
|
||||
[u.existing ossuary]
|
||||
::
|
||||
:- next-bone.ossuary
|
||||
:+ (add 4 next-bone.ossuary)
|
||||
(~(put by by-duct.ossuary) duct next-bone.ossuary)
|
||||
(~(put by by-bone.ossuary) next-bone.ossuary duct)
|
||||
:: +make-bone-wire: encode ship and bone in wire for sending to vane
|
||||
::
|
||||
++ make-bone-wire
|
||||
|= [her=ship =bone]
|
||||
^- wire
|
||||
::
|
||||
/bone/(scot %p her)/(scot %ud bone)
|
||||
:: +parse-bone-wire: decode ship and bone from wire from local vane
|
||||
::
|
||||
++ parse-bone-wire
|
||||
|= =wire
|
||||
^- [her=ship =bone]
|
||||
::
|
||||
~| %ames-wire-bone^wire
|
||||
?> ?=([%bone @ @ ~] wire)
|
||||
[`@p`(slav %p i.t.wire) `@ud`(slav %ud i.t.t.wire)]
|
||||
:: +make-pump-timer-wire: construct wire for |packet-pump timer
|
||||
::
|
||||
++ make-pump-timer-wire
|
||||
|= [her=ship =bone]
|
||||
^- wire
|
||||
/pump/(scot %p her)/(scot %ud bone)
|
||||
:: +parse-pump-timer-wire: parse .her and .bone from |packet-pump wire
|
||||
::
|
||||
++ parse-pump-timer-wire
|
||||
|= =wire
|
||||
^- (unit [her=ship =bone])
|
||||
::
|
||||
~| %ames-wire-timer^wire
|
||||
?. ?=([%pump @ @ ~] wire)
|
||||
~
|
||||
?~ ship=`(unit @p)`(slaw %p i.t.wire)
|
||||
~
|
||||
?~ bone=`(unit @ud)`(slaw %ud i.t.t.wire)
|
||||
~
|
||||
`[u.ship u.bone]
|
||||
:: +derive-symmetric-key: $symmetric-key from $private-key and $public-key
|
||||
::
|
||||
:: Assumes keys have a tag on them like the result of the |ex:crub core.
|
||||
::
|
||||
++ derive-symmetric-key
|
||||
|= [=public-key =private-key]
|
||||
^- symmetric-key
|
||||
::
|
||||
?> =('b' (end 3 1 public-key))
|
||||
=. public-key (rsh 8 1 (rsh 3 1 public-key))
|
||||
::
|
||||
?> =('B' (end 3 1 private-key))
|
||||
=. private-key (rsh 8 1 (rsh 3 1 private-key))
|
||||
::
|
||||
`@`(shar:ed:crypto public-key private-key)
|
||||
:: +encrypt: encrypt $shut-packet into atomic packet content
|
||||
::
|
||||
++ encrypt
|
||||
|= [=symmetric-key plaintext=shut-packet]
|
||||
^- @
|
||||
::
|
||||
=? meat.plaintext
|
||||
?& ?=(%& -.meat.plaintext)
|
||||
(gth (met 13 fragment.p.meat.plaintext) 1)
|
||||
==
|
||||
%_ meat.plaintext
|
||||
fragment.p
|
||||
(cut 13 [[fragment-num 1] fragment]:p.meat.plaintext)
|
||||
==
|
||||
(en:crub:crypto symmetric-key (jam plaintext))
|
||||
:: +decrypt: decrypt packet content to a $shut-packet or die
|
||||
::
|
||||
++ decrypt
|
||||
|= [=symmetric-key ciphertext=@]
|
||||
^- shut-packet
|
||||
::
|
||||
;; shut-packet
|
||||
%- cue
|
||||
%- need
|
||||
(de:crub:crypto symmetric-key ciphertext)
|
||||
:: +encode-packet: serialize a packet into a bytestream
|
||||
::
|
||||
++ encode-packet
|
||||
|= packet
|
||||
^- blob
|
||||
::
|
||||
=/ sndr-meta (encode-ship-metadata sndr)
|
||||
=/ rcvr-meta (encode-ship-metadata rcvr)
|
||||
:: body: <<sndr rcvr (jam [origin content])>>
|
||||
::
|
||||
:: The .sndr and .rcvr ship addresses are encoded with fixed
|
||||
:: lengths specified by the packet header. They live outside
|
||||
:: the jammed-data section to simplify packet filtering in the
|
||||
:: interpreter.
|
||||
::
|
||||
=/ body=@
|
||||
;: mix
|
||||
sndr
|
||||
(lsh 3 size.sndr-meta rcvr)
|
||||
(lsh 3 (add size.sndr-meta size.rcvr-meta) (jam [origin content]))
|
||||
==
|
||||
:: header: 32-bit header assembled from bitstreams of fields
|
||||
::
|
||||
:: <<version checksum sndr-rank rcvr-rank encryption-type unused>>
|
||||
:: 4 bits at the end of the header are unused.
|
||||
::
|
||||
=/ header=@
|
||||
%+ can 0
|
||||
:~ [3 protocol-version]
|
||||
[20 (mug body)]
|
||||
[2 rank.sndr-meta]
|
||||
[2 rank.rcvr-meta]
|
||||
[5 ?:(encrypted %0 %1)]
|
||||
==
|
||||
:: result is <<header body>>
|
||||
::
|
||||
(mix header (lsh 5 1 body))
|
||||
:: +decode-packet: deserialize packet from bytestream or crash
|
||||
::
|
||||
++ decode-packet
|
||||
|= =blob
|
||||
^- packet
|
||||
:: first 32 (2^5) bits are header; the rest is body
|
||||
::
|
||||
=/ header (end 5 1 blob)
|
||||
=/ body (rsh 5 1 blob)
|
||||
::
|
||||
=/ version (end 0 3 header)
|
||||
=/ checksum (cut 0 [3 20] header)
|
||||
=/ sndr-size (decode-ship-size (cut 0 [23 2] header))
|
||||
=/ rcvr-size (decode-ship-size (cut 0 [25 2] header))
|
||||
=/ encrypted ?+((cut 0 [27 5] header) !! %0 %.y, %1 %.n)
|
||||
::
|
||||
=/ =dyad
|
||||
:- sndr=(end 3 sndr-size body)
|
||||
rcvr=(cut 3 [sndr-size rcvr-size] body)
|
||||
::
|
||||
?. =(protocol-version version)
|
||||
~| %ames-protocol^version^dyad !!
|
||||
?. =(checksum (end 0 20 (mug body)))
|
||||
~| %ames-checksum^dyad !!
|
||||
::
|
||||
=+ ~| %ames-invalid-packet
|
||||
;; [origin=(unit lane) content=*]
|
||||
~| %ames-invalid-noun
|
||||
%- cue
|
||||
(rsh 3 (add rcvr-size sndr-size) body)
|
||||
::
|
||||
[dyad encrypted origin content]
|
||||
:: +decode-ship-size: decode a 2-bit ship type specifier into a byte width
|
||||
::
|
||||
:: Type 0: galaxy or star -- 2 bytes
|
||||
:: Type 1: planet -- 4 bytes
|
||||
:: Type 2: moon -- 8 bytes
|
||||
:: Type 3: comet -- 16 bytes
|
||||
::
|
||||
++ decode-ship-size
|
||||
|= rank=@
|
||||
^- @
|
||||
::
|
||||
?+ rank !!
|
||||
%0 2
|
||||
%1 4
|
||||
%2 8
|
||||
%3 16
|
||||
==
|
||||
:: +encode-ship-metadata: produce size (in bytes) and address rank for .ship
|
||||
::
|
||||
:: 0: galaxy or star
|
||||
:: 1: planet
|
||||
:: 2: moon
|
||||
:: 3: comet
|
||||
::
|
||||
++ encode-ship-metadata
|
||||
|= =ship
|
||||
^- [size=@ =rank]
|
||||
::
|
||||
=/ size=@ (met 3 ship)
|
||||
::
|
||||
?: (lte size 2) [2 %0]
|
||||
?: (lte size 4) [4 %1]
|
||||
?: (lte size 8) [8 %2]
|
||||
[16 %3]
|
||||
--
|
||||
|
@ -6,31 +6,43 @@
|
||||
::
|
||||
=/ nec vane
|
||||
=/ bud vane
|
||||
=/ comet vane
|
||||
::
|
||||
=. our.nec ~nec
|
||||
=. now.nec ~1111.1.1
|
||||
=. eny.nec 0xdead.beef
|
||||
=. rof.nec |=(* ``[%noun !>(*(list turf))])
|
||||
::
|
||||
=. our.bud ~bud
|
||||
=. now.bud ~1111.1.1
|
||||
=. eny.bud 0xbeef.dead
|
||||
=. rof.bud |=(* ``[%noun !>(*(list turf))])
|
||||
::
|
||||
=. our.nec ~nec
|
||||
=. now.nec ~1111.1.1
|
||||
=. eny.nec 0xdead.beef
|
||||
=. life.ames-state.nec 2
|
||||
=. scry-gate.nec |=(* ``[%noun !>(*(list turf))])
|
||||
=. crypto-core.ames-state.nec (pit:nu:crub:crypto 512 (shaz 'nec'))
|
||||
=. crypto-core.ames-state.bud (pit:nu:crub:crypto 512 (shaz 'bud'))
|
||||
::
|
||||
=/ nec-pub pub:ex:crypto-core.ames-state.nec
|
||||
=/ nec-sec sec:ex:crypto-core.ames-state.nec
|
||||
::
|
||||
=. our.bud ~bud
|
||||
=. now.bud ~1111.1.1
|
||||
=. eny.bud 0xbeef.dead
|
||||
=. life.ames-state.bud 3
|
||||
=. scry-gate.bud |=(* ``[%noun !>(*(list turf))])
|
||||
=. crypto-core.ames-state.bud (pit:nu:crub:crypto 512 (shaz 'bud'))
|
||||
=/ bud-pub pub:ex:crypto-core.ames-state.bud
|
||||
=/ bud-sec sec:ex:crypto-core.ames-state.bud
|
||||
::
|
||||
=. our.comet ~bosrym-podwyl-magnes-dacrys--pander-hablep-masrym-marbud
|
||||
=. now.comet ~1111.1.1
|
||||
=. eny.comet 0xbeef.cafe
|
||||
=. scry-gate.comet |=(* ``[%noun !>(*(list turf))])
|
||||
=. crypto-core.ames-state.comet
|
||||
%- nol:nu:crub:crypto
|
||||
0w9N.5uIvA.Jg0cx.NCD2R.o~MtZ.uEQOB.9uTbp.6LHvg.0yYTP.
|
||||
3q3td.T4UF0.d5sDL.JGpZq.S3A92.QUuWg.IHdw7.izyny.j9W92
|
||||
=/ comet-pub pub:ex:crypto-core.ames-state.comet
|
||||
=/ comet-sec sec:ex:crypto-core.ames-state.comet
|
||||
::
|
||||
=/ nec-sym (derive-symmetric-key:vane bud-pub nec-sec)
|
||||
=/ bud-sym (derive-symmetric-key:vane nec-pub bud-sec)
|
||||
::
|
||||
?> =(nec-sym bud-sym)
|
||||
::
|
||||
=. life.ames-state.nec 2
|
||||
=/ comet-sym (derive-symmetric-key:vane bud-pub comet-sec)
|
||||
::
|
||||
=. peers.ames-state.nec
|
||||
%+ ~(put by peers.ames-state.nec) ~bud
|
||||
=| =peer-state:ames
|
||||
@ -43,7 +55,6 @@
|
||||
=. route.peer-state `[direct=%.y `lane:ames`[%& ~nec]]
|
||||
[%known peer-state]
|
||||
::
|
||||
=. life.ames-state.bud 3
|
||||
=. peers.ames-state.bud
|
||||
%+ ~(put by peers.ames-state.bud) ~nec
|
||||
=| =peer-state:ames
|
||||
@ -106,9 +117,10 @@
|
||||
::
|
||||
=/ =packet:ames
|
||||
:* [sndr=~nec rcvr=~bud]
|
||||
encrypted=%.n
|
||||
sndr-tick=0b10
|
||||
rcvr-tick=0b11
|
||||
origin=~
|
||||
content=[12 13]
|
||||
content=0xdead.beef
|
||||
==
|
||||
::
|
||||
=/ encoded (encode-packet:vane packet)
|
||||
@ -118,6 +130,50 @@
|
||||
!> packet
|
||||
!> decoded
|
||||
::
|
||||
++ test-origin-encoding ^- tang
|
||||
::
|
||||
=/ =packet:ames
|
||||
:* [sndr=~nec rcvr=~bud]
|
||||
sndr-tick=0b10
|
||||
rcvr-tick=0b11
|
||||
origin=`0xbeef.cafe.beef
|
||||
content=0xdead.beef
|
||||
==
|
||||
::
|
||||
=/ encoded (encode-packet:vane packet)
|
||||
=/ decoded (decode-packet:vane encoded)
|
||||
::
|
||||
%+ expect-eq
|
||||
!> packet
|
||||
!> decoded
|
||||
::
|
||||
++ test-shut-packet-encoding ^- tang
|
||||
::
|
||||
=/ =shut-packet:ames
|
||||
:+ bone=17 message-num=18
|
||||
[%& num-fragments=1 fragment-num=1 fragment=`@`0xdead.beef]
|
||||
::
|
||||
=/ =packet:ames
|
||||
(encode-shut-packet:ames shut-packet nec-sym ~marnec ~marbud-marbud 3 17)
|
||||
::
|
||||
=/ decoded (decode-shut-packet:ames packet nec-sym 3 17)
|
||||
::
|
||||
%+ expect-eq
|
||||
!> shut-packet
|
||||
!> decoded
|
||||
::
|
||||
++ test-shut-packet-associated-data ^- tang
|
||||
::
|
||||
=/ =shut-packet:ames
|
||||
:+ bone=17 message-num=18
|
||||
[%& num-fragments=1 fragment-num=1 fragment=`@`0xdead.beef]
|
||||
::
|
||||
=/ =packet:ames
|
||||
(encode-shut-packet:ames shut-packet nec-sym ~marnec ~marbud-marbud 3 1)
|
||||
::
|
||||
%- expect-fail
|
||||
|.((decode-shut-packet:ames packet nec-sym 3 17))
|
||||
::
|
||||
++ test-alien-encounter ^- tang
|
||||
::
|
||||
=/ lane-foo=lane:ames [%| `@ux``@`%lane-foo]
|
||||
@ -125,18 +181,19 @@
|
||||
=/ =plea:ames [%g /talk [%first %post]]
|
||||
::
|
||||
=/ =shut-packet:ames
|
||||
:* sndr-life=4
|
||||
rcvr-life=3
|
||||
bone=1
|
||||
:* bone=1
|
||||
message-num=1
|
||||
[%& num-fragments=1 fragment-num=0 (jam plea)]
|
||||
==
|
||||
::
|
||||
=/ =packet:ames
|
||||
:* [sndr=~bus rcvr=~bud]
|
||||
encrypted=%.y
|
||||
origin=~
|
||||
content=(encrypt:vane nec-sym shut-packet)
|
||||
%: encode-shut-packet:vane
|
||||
shut-packet
|
||||
nec-sym
|
||||
~bus
|
||||
~bud
|
||||
sndr-life=4
|
||||
rcvr-life=3
|
||||
==
|
||||
::
|
||||
=/ =blob:ames (encode-packet:vane packet)
|
||||
@ -170,6 +227,56 @@
|
||||
!> (sy ,.moves3)
|
||||
==
|
||||
::
|
||||
++ test-comet-encounter ^- tang
|
||||
::
|
||||
=/ lane-foo=lane:ames [%| `@ux``@`%lane-foo]
|
||||
::
|
||||
=/ =open-packet:ames
|
||||
:* public-key=`@`comet-pub
|
||||
sndr=our.comet
|
||||
sndr-life=1
|
||||
rcvr=~bud
|
||||
rcvr-life=3
|
||||
==
|
||||
=/ packet
|
||||
(encode-open-packet:vane open-packet crypto-core.ames-state.comet)
|
||||
=/ blob (encode-packet:vane packet)
|
||||
::
|
||||
=^ moves0 bud (call bud ~[//unix] %hear lane-foo blob)
|
||||
::
|
||||
=/ =plea:ames [%g /talk [%first %post]]
|
||||
=/ =shut-packet:ames
|
||||
:* bone=1
|
||||
message-num=1
|
||||
[%& num-fragments=1 fragment-num=0 (jam plea)]
|
||||
==
|
||||
=/ =packet:ames
|
||||
%: encode-shut-packet:vane
|
||||
shut-packet
|
||||
comet-sym
|
||||
our.comet
|
||||
~bud
|
||||
sndr-life=1
|
||||
rcvr-life=3
|
||||
==
|
||||
=/ blob (encode-packet:vane packet)
|
||||
=^ moves1 bud (call bud ~[//unix] %hear lane-foo blob)
|
||||
::
|
||||
;: weld
|
||||
%+ expect-eq
|
||||
!> ~
|
||||
!> moves0
|
||||
::
|
||||
%+ expect-eq
|
||||
!> :~ :* ~[//unix] %pass /qos %d %flog %text
|
||||
"; {<our.comet>} is your neighbor"
|
||||
==
|
||||
:* ~[//unix] %pass /bone/(scot %p our.comet)/1
|
||||
%g %plea our.comet plea
|
||||
== ==
|
||||
!> moves1
|
||||
==
|
||||
::
|
||||
++ test-message-flow ^- tang
|
||||
:: ~nec -> %plea -> ~bud
|
||||
::
|
||||
|
@ -66,11 +66,12 @@
|
||||
/* u3_head: ames packet header
|
||||
*/
|
||||
typedef struct _u3_head {
|
||||
c3_o sim_o; // is ames protocol?
|
||||
c3_y ver_y; // protocol version
|
||||
c3_l mug_l; // truncated mug hash of u3_body
|
||||
c3_y sac_y; // sender class
|
||||
c3_y rac_y; // receiver class
|
||||
c3_o enc_o; // encrypted?
|
||||
c3_l mug_l; // truncated mug hash of u3_body
|
||||
c3_o rel_o; // relayed?
|
||||
} u3_head;
|
||||
|
||||
/* u3_body: ames packet body
|
||||
@ -78,8 +79,12 @@
|
||||
typedef struct _u3_body {
|
||||
c3_d sen_d[2]; // sender
|
||||
c3_d rec_d[2]; // receiver
|
||||
c3_w con_w; // jam size
|
||||
c3_y* con_y; // (jam [origin content])
|
||||
c3_y sic_y; // sender life tick
|
||||
c3_y ric_y; // receiver life tick
|
||||
c3_s con_s; // content size
|
||||
c3_y* con_y; // content
|
||||
c3_d rog_d; // origin lane (optional)
|
||||
c3_l mug_l; // checksum
|
||||
} u3_body;
|
||||
|
||||
/* u3_panc: deconstructed incoming packet
|
||||
@ -140,14 +145,6 @@ _ames_panc_free(u3_panc* pac_u)
|
||||
c3_free(pac_u);
|
||||
}
|
||||
|
||||
/* _ames_mug_body(): truncated (20 least-significant bits) mug hash of bytes
|
||||
*/
|
||||
static c3_l
|
||||
_ames_mug_body(c3_w len_w, c3_y* byt_y)
|
||||
{
|
||||
return u3r_mug_bytes(byt_y, len_w) & 0xfffff;
|
||||
}
|
||||
|
||||
/* _ames_sift_head(): parse packet header.
|
||||
*/
|
||||
static c3_o
|
||||
@ -158,36 +155,20 @@ _ames_sift_head(u3_head* hed_u, c3_y buf_y[4])
|
||||
| (buf_y[2] << 16)
|
||||
| (buf_y[3] << 24);
|
||||
|
||||
// XX only version 0 currently recognized
|
||||
// first three bits are reserved
|
||||
//
|
||||
hed_u->ver_y = hed_w & 0x7;
|
||||
hed_u->mug_l = (hed_w >> 3) & 0xfffff; // 20 bits
|
||||
hed_u->sac_y = (hed_w >> 23) & 0x3;
|
||||
hed_u->rac_y = (hed_w >> 25) & 0x3;
|
||||
hed_u->enc_o = (hed_w >> 27) & 0x1;
|
||||
return c3y;
|
||||
hed_u->sim_o = (hed_w >> 3) & 0x1;
|
||||
hed_u->ver_y = (hed_w >> 4) & 0x7;
|
||||
hed_u->sac_y = (hed_w >> 7) & 0x3;
|
||||
hed_u->rac_y = (hed_w >> 9) & 0x3;
|
||||
hed_u->mug_l = (hed_w >> 11) & 0xfffff; // 20 bits
|
||||
hed_u->rel_o = (hed_w >> 31) & 0x1;
|
||||
|
||||
// reject packets that don't even claim to be ames packets
|
||||
//
|
||||
return hed_u->sim_o;
|
||||
}
|
||||
|
||||
/* _ames_etch_head(): serialize packet header.
|
||||
*/
|
||||
static void
|
||||
_ames_etch_head(u3_head* hed_u, c3_y buf_y[4])
|
||||
{
|
||||
c3_w hed_w = hed_u->ver_y
|
||||
| (hed_u->mug_l << 3)
|
||||
| (hed_u->sac_y << 23)
|
||||
| (hed_u->rac_y << 25)
|
||||
| (hed_u->enc_o << 27);
|
||||
|
||||
// only version 0 currently recognized
|
||||
//
|
||||
c3_assert( 0 == hed_u->ver_y );
|
||||
|
||||
buf_y[0] = hed_w & 0xff;
|
||||
buf_y[1] = (hed_w >> 8) & 0xff;
|
||||
buf_y[2] = (hed_w >> 16) & 0xff;
|
||||
buf_y[3] = (hed_w >> 24) & 0xff;
|
||||
}
|
||||
|
||||
/* _ames_chub_bytes(): c3_y[8] to c3_d
|
||||
** XX factor out, deduplicate with other conversions
|
||||
@ -254,57 +235,106 @@ _ames_sift_body(u3_head* hed_u,
|
||||
c3_w len_w,
|
||||
c3_y* bod_y)
|
||||
{
|
||||
c3_y sen_y = 2 << hed_u->sac_y;
|
||||
c3_y rec_y = 2 << hed_u->rac_y;
|
||||
c3_y rog_y, sen_y, rec_y;
|
||||
|
||||
if ( (sen_y + rec_y) >= len_w ) {
|
||||
rog_y = ( c3y == hed_u->rel_o )? 6 : 0;
|
||||
|
||||
sen_y = 2 << hed_u->sac_y;
|
||||
rec_y = 2 << hed_u->rac_y;
|
||||
|
||||
if ( (1 + sen_y + rec_y + rog_y) >= len_w ) {
|
||||
return c3n;
|
||||
}
|
||||
else {
|
||||
_ames_ship_to_chubs(bod_u->sen_d, sen_y, bod_y);
|
||||
_ames_ship_to_chubs(bod_u->rec_d, rec_y, bod_y + sen_y);
|
||||
c3_y* gob_y;
|
||||
c3_s gob_s;
|
||||
|
||||
if ( rog_y) {
|
||||
c3_y rag_y[8] = {0};
|
||||
memcpy(rag_y, bod_y, rog_y);
|
||||
bod_u->rog_d = _ames_chub_bytes(rag_y);
|
||||
}
|
||||
else {
|
||||
bod_u->rog_d = 0;
|
||||
}
|
||||
|
||||
gob_y = bod_y + rog_y;
|
||||
gob_s = len_w - rog_y;
|
||||
|
||||
bod_u->mug_l = u3r_mug_bytes(gob_y, gob_s) & 0xfffff;
|
||||
|
||||
bod_u->sic_y = gob_y[0] & 0xf;
|
||||
bod_u->ric_y = (gob_y[0] >> 4) & 0xf;
|
||||
|
||||
_ames_ship_to_chubs(bod_u->sen_d, sen_y, gob_y + 1);
|
||||
_ames_ship_to_chubs(bod_u->rec_d, rec_y, gob_y + 1 + sen_y);
|
||||
|
||||
bod_u->con_s = gob_s - 1 - sen_y - rec_y;
|
||||
bod_u->con_y = gob_y + 1 + sen_y + rec_y;
|
||||
|
||||
bod_u->con_w = len_w - sen_y - rec_y;
|
||||
bod_u->con_y = bod_y + sen_y + rec_y;
|
||||
return c3y;
|
||||
}
|
||||
}
|
||||
|
||||
/* _ames_etch_head(): serialize packet header.
|
||||
*/
|
||||
static void
|
||||
_ames_etch_head(u3_head* hed_u, c3_y buf_y[4])
|
||||
{
|
||||
c3_w hed_w = ((hed_u->sim_o & 0x1) << 3)
|
||||
^ ((hed_u->ver_y & 0x7) << 4)
|
||||
^ ((hed_u->sac_y & 0x3) << 7)
|
||||
^ ((hed_u->rac_y & 0x3) << 9)
|
||||
^ ((hed_u->mug_l & 0xfffff) << 11)
|
||||
^ ((hed_u->rel_o & 0x1) << 31);
|
||||
|
||||
// only version 0 currently recognized
|
||||
//
|
||||
c3_assert( 0 == hed_u->ver_y ); // XX remove after testing
|
||||
|
||||
buf_y[0] = hed_w & 0xff;
|
||||
buf_y[1] = (hed_w >> 8) & 0xff;
|
||||
buf_y[2] = (hed_w >> 16) & 0xff;
|
||||
buf_y[3] = (hed_w >> 24) & 0xff;
|
||||
}
|
||||
|
||||
/* _ames_etch_pack(): serialize packet header and body.
|
||||
*/
|
||||
static c3_w
|
||||
_ames_etch_pack(u3_head* hed_u,
|
||||
u3_body* bod_u,
|
||||
c3_o mug_o,
|
||||
c3_y** out_y)
|
||||
{
|
||||
// start with the body
|
||||
//
|
||||
c3_y sen_y = 2 << hed_u->sac_y; // sender len
|
||||
c3_y rec_y = 2 << hed_u->rac_y; // receiver len
|
||||
c3_w bod_w = sen_y + rec_y + bod_u->con_w; // body len
|
||||
c3_w len_w = 4 + bod_w; // packet len
|
||||
c3_y* pac_y = c3_malloc(len_w);
|
||||
c3_y* bod_y = pac_y + 4;
|
||||
c3_y sen_y = 2 << hed_u->sac_y; // sender len
|
||||
c3_y rec_y = 2 << hed_u->rac_y; // receiver len
|
||||
c3_y rog_y = ( c3y == hed_u->rel_o )? 6 : 0; // origin len
|
||||
c3_w bod_w = rog_y + 1 + sen_y + rec_y + bod_u->con_s; // body len
|
||||
c3_w len_w = 4 + bod_w; // packet len
|
||||
c3_y* pac_y = c3_malloc(len_w); // output buf
|
||||
c3_y* bod_y = pac_y + 4; // body cursor
|
||||
c3_y* gob_y = bod_y + rog_y; // after origin
|
||||
|
||||
_ames_ship_of_chubs(bod_u->sen_d, sen_y, bod_y);
|
||||
_ames_ship_of_chubs(bod_u->rec_d, rec_y, bod_y + sen_y);
|
||||
|
||||
{
|
||||
c3_y* con_y = bod_y + sen_y + rec_y;
|
||||
memcpy(con_y, bod_u->con_y, bod_u->con_w);
|
||||
}
|
||||
|
||||
// if we updated the origin lane, we need to update the mug too
|
||||
//
|
||||
if ( c3y == mug_o ) {
|
||||
hed_u->mug_l = _ames_mug_body(bod_w, bod_y);
|
||||
}
|
||||
|
||||
// now we can serialize the head
|
||||
// serialize the head
|
||||
//
|
||||
_ames_etch_head(hed_u, pac_y);
|
||||
|
||||
// serialize the origin, if present
|
||||
//
|
||||
if ( rog_y ) {
|
||||
c3_y rag_y[8] = {0};
|
||||
_ames_bytes_chub(rag_y, bod_u->rog_d);
|
||||
memcpy(bod_y, rag_y, rog_y);
|
||||
}
|
||||
|
||||
// serialize the body
|
||||
//
|
||||
gob_y[0] = (bod_u->sic_y & 0xf) ^ ((bod_u->ric_y & 0xf) << 4);
|
||||
|
||||
_ames_ship_of_chubs(bod_u->sen_d, sen_y, gob_y + 1);
|
||||
_ames_ship_of_chubs(bod_u->rec_d, rec_y, gob_y + 1 + sen_y);
|
||||
|
||||
memcpy(gob_y + 1 + sen_y + rec_y, bod_u->con_y, bod_u->con_s);
|
||||
|
||||
*out_y = pac_y;
|
||||
return len_w;
|
||||
}
|
||||
@ -371,28 +401,29 @@ _ames_send(u3_pact* pac_u)
|
||||
*/
|
||||
u3_lane
|
||||
u3_ames_decode_lane(u3_atom lan) {
|
||||
u3_noun cud, tag, pip, por;
|
||||
|
||||
cud = u3ke_cue(lan);
|
||||
u3x_trel(cud, &tag, &pip, &por);
|
||||
c3_assert( c3__ipv4 == tag );
|
||||
|
||||
u3_lane lan_u;
|
||||
lan_u.pip_w = u3r_word(0, pip);
|
||||
c3_d lan_d;
|
||||
|
||||
c3_assert( _(u3a_is_cat(por)) );
|
||||
c3_assert( por < 65536 );
|
||||
lan_u.por_s = por;
|
||||
c3_assert( c3y == u3r_safe_chub(lan, &lan_d) );
|
||||
u3z(lan);
|
||||
|
||||
u3z(cud);
|
||||
lan_u.pip_w = (c3_w)lan_d;
|
||||
lan_u.por_s = (c3_s)(lan_d >> 32);
|
||||
return lan_u;
|
||||
}
|
||||
|
||||
/* u3_ames_encode_lane(): serialize lane to jammed noun
|
||||
/* u3_ames_lane_to_chub(): serialize lane to double-word
|
||||
*/
|
||||
c3_d
|
||||
u3_ames_lane_to_chub(u3_lane lan) {
|
||||
return ((c3_d)lan.por_s << 32) ^ (c3_d)lan.pip_w;
|
||||
}
|
||||
|
||||
/* u3_ames_encode_lane(): serialize lane to noun
|
||||
*/
|
||||
u3_atom
|
||||
u3_ames_encode_lane(u3_lane lan) {
|
||||
return u3ke_jam(u3nt(c3__ipv4, u3i_words(1, &lan.pip_w), lan.por_s));
|
||||
return u3i_chub(u3_ames_lane_to_chub(lan));
|
||||
}
|
||||
|
||||
/* _ames_lane_into_cache(): put las for who into cache, including timestamp
|
||||
@ -438,57 +469,18 @@ _ames_lane_from_cache(u3p(u3h_root) lax_p, u3_noun who) {
|
||||
static u3_noun
|
||||
_ames_serialize_packet(u3_panc* pac_u, c3_o dop_o)
|
||||
{
|
||||
c3_o nal_o = c3n;
|
||||
|
||||
// update the body's lane, if desired
|
||||
// update the body's lane, if:
|
||||
// - we're supposed to (dop_o)
|
||||
// - it hasn't already been updated (rel_o)
|
||||
// - sender is not a galaxy
|
||||
//
|
||||
if ( c3y == dop_o ) {
|
||||
// unpack (jam [(unit lane) body])
|
||||
//
|
||||
u3_noun lon, bod;
|
||||
{
|
||||
//NOTE we checked for cue safety in _ames_recv_cb
|
||||
//
|
||||
u3_weak old = u3s_cue_xeno_with(pac_u->sam_u->sil_u,
|
||||
pac_u->bod_u.con_w,
|
||||
pac_u->bod_u.con_y);
|
||||
u3x_cell(u3x_good(old), &lon, &bod);
|
||||
u3k(lon); u3k(bod);
|
||||
u3z(old);
|
||||
}
|
||||
|
||||
// only replace the lane if it was ~
|
||||
//
|
||||
//NOTE this sets an opaque lane even in the "sender is galaxy" case,
|
||||
// but that doesn't matter: ames.hoon ignores origin in that case,
|
||||
// always using the appropriate galaxy lane instead.
|
||||
//
|
||||
if ( u3_nul == lon ) {
|
||||
c3_w con_w;
|
||||
c3_y* con_y;
|
||||
|
||||
u3z(lon);
|
||||
lon = u3nt(u3_nul, c3n, u3_ames_encode_lane(pac_u->ore_u));
|
||||
nal_o = c3y;
|
||||
|
||||
// XX off-loom jam?
|
||||
//
|
||||
{
|
||||
u3_noun jam = u3ke_jam(u3nc(lon, bod));
|
||||
con_w = u3r_met(3, jam);
|
||||
con_y = c3_malloc(con_w);
|
||||
u3r_bytes(0, con_w, con_y, jam);
|
||||
u3z(jam);
|
||||
}
|
||||
|
||||
c3_free(pac_u->ptr_v);
|
||||
pac_u->ptr_v = con_y;
|
||||
pac_u->bod_u.con_y = con_y;
|
||||
pac_u->bod_u.con_w = con_w;
|
||||
}
|
||||
else {
|
||||
u3z(lon); u3z(bod);
|
||||
}
|
||||
if ( c3y == dop_o
|
||||
&& c3n == pac_u->hed_u.rel_o
|
||||
&& !( ( 256 > pac_u->bod_u.sen_d[0] )
|
||||
&& ( 0 == pac_u->bod_u.sen_d[1] ) ) )
|
||||
{
|
||||
pac_u->hed_u.rel_o = c3y;
|
||||
pac_u->bod_u.rog_d = u3_ames_lane_to_chub(pac_u->ore_u);
|
||||
}
|
||||
|
||||
// serialize the packet
|
||||
@ -500,7 +492,7 @@ _ames_serialize_packet(u3_panc* pac_u, c3_o dop_o)
|
||||
c3_y* pac_y;
|
||||
c3_w len_w = _ames_etch_pack(&pac_u->hed_u,
|
||||
&pac_u->bod_u,
|
||||
nal_o, &pac_y);
|
||||
&pac_y);
|
||||
pac = u3i_bytes(len_w, pac_y);
|
||||
c3_free(pac_y);
|
||||
|
||||
@ -989,7 +981,8 @@ _ames_try_forward(u3_ames* sam_u,
|
||||
if ( (u3_none == lac) && (1000 < sam_u->sat_u.foq_d) ) {
|
||||
sam_u->sat_u.fod_d++;
|
||||
if ( 0 == (sam_u->sat_u.fod_d % 10000) ) {
|
||||
u3l_log("ames: dropped %" PRIu64 " forwards total\n", sam_u->sat_u.fod_d);
|
||||
u3l_log("ames: dropped %" PRIu64 " forwards total\n",
|
||||
sam_u->sat_u.fod_d);
|
||||
}
|
||||
|
||||
c3_free(hun_y);
|
||||
@ -1042,7 +1035,7 @@ _ames_try_forward(u3_ames* sam_u,
|
||||
}
|
||||
}
|
||||
|
||||
/* _ames_hear(): parse a (potential packet), dispatch appropriately.
|
||||
/* _ames_hear(): parse a (potential) packet, dispatch appropriately.
|
||||
*/
|
||||
static void
|
||||
_ames_hear(u3_ames* sam_u,
|
||||
@ -1073,7 +1066,8 @@ _ames_hear(u3_ames* sam_u,
|
||||
{
|
||||
sam_u->sat_u.hed_d++;
|
||||
if ( 0 == (sam_u->sat_u.hed_d % 100) ) {
|
||||
u3l_log("ames: %" PRIu64 " dropped, failed to read header\n", sam_u->sat_u.hed_d);
|
||||
u3l_log("ames: %" PRIu64 " dropped, failed to read header\n",
|
||||
sam_u->sat_u.hed_d);
|
||||
}
|
||||
|
||||
c3_free(hun_y);
|
||||
@ -1089,7 +1083,8 @@ _ames_hear(u3_ames* sam_u,
|
||||
{
|
||||
sam_u->sat_u.vet_d++;
|
||||
if ( 0 == (sam_u->sat_u.vet_d % 100) ) {
|
||||
u3l_log("ames: %" PRIu64 " dropped for version mismatch\n", sam_u->sat_u.vet_d);
|
||||
u3l_log("ames: %" PRIu64 " dropped for version mismatch\n",
|
||||
sam_u->sat_u.vet_d);
|
||||
}
|
||||
|
||||
c3_free(hun_y);
|
||||
@ -1100,26 +1095,26 @@ _ames_hear(u3_ames* sam_u,
|
||||
c3_w bod_w = len_w - 4;
|
||||
c3_y* bod_y = hun_y + 4;
|
||||
|
||||
// ensure the mug is valid
|
||||
// unpack and validate the body
|
||||
//
|
||||
if ( _ames_mug_body(bod_w, bod_y) != hed_u.mug_l ) {
|
||||
sam_u->sat_u.mut_d++;
|
||||
if ( 0 == (sam_u->sat_u.mut_d % 100) ) {
|
||||
u3l_log("ames: %" PRIu64 " dropped for invalid mug\n", sam_u->sat_u.mut_d);
|
||||
if ( (c3n == _ames_sift_body(&hed_u, &bod_u, bod_w, bod_y)) ) {
|
||||
sam_u->sat_u.bod_d++;
|
||||
if ( 0 == (sam_u->sat_u.bod_d % 100) ) {
|
||||
u3l_log("ames: %" PRIu64 " dropped, failed to read body\n",
|
||||
sam_u->sat_u.bod_d);
|
||||
}
|
||||
|
||||
c3_free(hun_y);
|
||||
return;
|
||||
}
|
||||
|
||||
// unpack and validate the body
|
||||
// ensure the mug is valid
|
||||
//
|
||||
if ( (c3n == _ames_sift_body(&hed_u, &bod_u, bod_w, bod_y))
|
||||
|| !ur_cue_test_with(sam_u->tes_u, bod_u.con_w, bod_u.con_y) )
|
||||
{
|
||||
sam_u->sat_u.bod_d++;
|
||||
if ( 0 == (sam_u->sat_u.bod_d % 100) ) {
|
||||
u3l_log("ames: %" PRIu64 " dropped, failed to read body\n", sam_u->sat_u.bod_d);
|
||||
if ( bod_u.mug_l != hed_u.mug_l ) {
|
||||
sam_u->sat_u.mut_d++;
|
||||
if ( 0 == (sam_u->sat_u.mut_d % 100) ) {
|
||||
u3l_log("ames: %" PRIu64 " dropped for invalid mug\n",
|
||||
sam_u->sat_u.mut_d);
|
||||
}
|
||||
|
||||
c3_free(hun_y);
|
||||
|
Loading…
Reference in New Issue
Block a user