gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gnunet-scheme] 82/324: Implement self-documenting ‘network structures’


From: gnunet
Subject: [gnunet-scheme] 82/324: Implement self-documenting ‘network structures’
Date: Tue, 21 Sep 2021 13:22:02 +0200

This is an automated email from the git hooks/post-receive script.

maxime-devos pushed a commit to branch master
in repository gnunet-scheme.

commit 6d35e88e79d42de2f02ce77554bda1d14e513127
Author: Maxime Devos <maximedevos@telenet.be>
AuthorDate: Wed Feb 17 21:03:47 2021 +0100

    Implement self-documenting ‘network structures’
    
    In contrast to scheme-bytestructures and
    (gnu gnunet utils netstruct), this allows associating
    a synopsis, a documention string (docstring) and arbitrary
    properties with structures and fields.
    
    Code compilation should be faster now as well and the
    compiled '.go' should be smaller due to less excessive
    use of syntax-rules.
    
    TODO: update old modules
    
    * Makefile.am (modules): compile new modules
      gnu/gnunet/netstruct/procedural.scm and
      gnu/gnunet/netstruct/syntactic.scm.
    * README.org (Network Structures): document new modules.
    * gnu/gnunet/crypto/struct.scm: use new module.
    * gnu/gnunet/hashcode/struct.scm: likewise.
    * gnu/gnunet/nse/struct.scm: likewise.
    * gnu/gnunet/util/struct.scm: likewise.
    * gnu/gnunet/netstruct/procedural.scm: new module
      for defining and using network structures
      procedurally.
    * gnu/gnunet/netstruct/syntactic.scm: likewise,
      but syntactically and with some inlining.
---
 Makefile.am                         |   5 +-
 README.org                          |  33 +++
 gnu/gnunet/crypto/struct.scm        | 146 ++++++------
 gnu/gnunet/hashcode/struct.scm      |  29 ++-
 gnu/gnunet/netstruct/procedural.scm | 416 +++++++++++++++++++++++++++++++++++
 gnu/gnunet/netstruct/syntactic.scm  | 427 ++++++++++++++++++++++++++++++++++++
 gnu/gnunet/nse/struct.scm           |  93 ++++----
 gnu/gnunet/util/struct.scm          |  69 +++---
 8 files changed, 1068 insertions(+), 150 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index 9c6aa67..3e85312 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -49,7 +49,10 @@ modules = \
   gnu/gnunet/util/struct.scm \
   gnu/gnunet/crypto/struct.scm \
   gnu/gnunet/hashcode/struct.scm \
-  gnu/gnunet/nse/struct.scm
+  gnu/gnunet/nse/struct.scm \
+  \
+  gnu/gnunet/netstruct/procedural.scm \
+  gnu/gnunet/netstruct/syntactic.scm
 
 dist_guilesite_DATA = $(modules)
 
diff --git a/README.org b/README.org
index 4c220f4..3a1ee1f 100644
--- a/README.org
+++ b/README.org
@@ -53,6 +53,39 @@
   + gnu/gnunet/concurrency/update.scm: a box with a value,
     that can be updated, resulting in a new box.  Updates
     can be waited upon.
+
+** Network structures
+   Features:
+
+   + structures are always architecture-independent
+     (no possible dependencies on the C ABI)
+   + big / little endianness distinction
+   + (almost) no runtime overhead over raw
+     slice-u8-ref & friends when using syntax API
+
+     (Some overhead is incurred due to type-checking)
+     TODO: verify expanded code
+   + structures can have various meta data
+     (e.g. docstring)  TODO write emacs functions
+     for looking up docstrings etc.
+
+   Not features (in contrast with scheme-bytestructures):
+   - not extensible with new kinds of network structure types.
+
+   How to use:
+   + define network structures in a (... struct) module
+     using (gnu gnunet netstruct syntactic) or
+     (gnu gnunet netstruct procedural)
+   + use network structures /outside/ the (... struct) module
+     using (gnu gnunet netstruct syntactic)
+     or (gnu gnunet netstruct procedural) module.
+
+     The former is preferred as offsets and sizes etc.
+     are inlined
+
+     TODO: make sure no references to (... struct) modules
+     are created when accessing network structures with
+     (gnu gnunet netstruct syntactic).
 * Conventions
 ** Fiddling with options
    Options like ‘priority’, ‘anonymity’, ‘replication’
diff --git a/gnu/gnunet/crypto/struct.scm b/gnu/gnunet/crypto/struct.scm
index 584c979..7a2812e 100644
--- a/gnu/gnunet/crypto/struct.scm
+++ b/gnu/gnunet/crypto/struct.scm
@@ -53,92 +53,104 @@
          /ecdsa-private-key /eddsa-private-key
          /symmetric-session-key
          /challenge-nonce-p)
-  (import (gnu gnunet hashcode struct)
-         (gnu gnunet utils netstruct)
-         (only (rnrs base)
-               begin define-syntax))
+  (import (only (gnu gnunet hashcode struct) /hashcode:256)
+         (only (gnu gnunet netstruct syntactic)
+               define-type structure/packed)
+         (only (gnu gnunet netstruct procedural) u8vector)
+         (only (rnrs base) begin))
   (begin
-    ;; An ECC signature using EdDSA.
-    ;; See cr.yp.to/papers.html#ed25519
-    (define-syntax /eddsa-signature
+    (define-type /eddsa-signature
       (structure/packed
-       ;; R value.
-       ("r" (u8vector 64))
-       ;; S value.
-       ("s" (u8vector 64))))
+       (synopsis "An ECC signature using EdDSA.")
+       (documentation "See cr.yp.to/papers.html#ed25519")
+       (field (r (u8vector 64))
+             (synopsis "R value"))
+       (field (s (u8vector 64))
+             (synopsis "S value"))))
 
-    ;; An ECC signature using ECDSA.
-    (define-syntax /ecdsa-signature
+    (define-type /ecdsa-signature
       (structure/packed
-       ;; R value.
-       ("r" (u8vector 64))
-       ;; S value.
-       ("s" (u8vector 64))))
+       (synopsis "An ECC signature using ECDSA.")
+       (field (r (u8vector 64))
+             (synopsis "R value"))
+       (field (s (u8vector 64))
+             (synopsis "S value"))))
 
-    ;; Public ECC key (always for curve Ed25519) encoded in a format
-    ;; suitable for network transmission and EdDSA signatures.  Refer
-    ;; to section 5.1.3 of rfc8032, for a thorough explanation of how
-    ;; this value maps to the x- and y-coordinates.
-    (define-syntax /eddsa-public-key
+    (define-type /eddsa-public-key
       (structure/packed
-       ;; Point Q consists of a y-value mod p (256 bits); the x-value is
-       ;; always positive. The point is stored in Ed25519 standard
-       ;; compact format.
-       ("q" (u8vector 64))))
+       (documentation "Public ECC key (always for curve Ed25519) encoded in
+a format suitable for network transmission and EdDSA signatures.
+Refer to section 5.1.3 of rfc8032, for a thorough explanation of how this
+value maps to the x- and y-coordinates.")
+       (field (q (u8vector 64))
+             (documentation "Point Q consists of a y-value mod p (256 bits);
+the x-value is always positive. The point is stored in Ed25519 standard
+compact format."))))
 
-    ;; Public ECC key (always for Curve25519) encoded in a format suitable
-    ;; for network transmission and ECDSA signatures.
-    (define-syntax /ecdsa-public-key
+    (define-type /ecdsa-public-key
       (structure/packed
-       ;; Q consists of an x- and a y-value, each mod p (256 bits), given
-       ;; here in affine coordinates and Ed25519 standard compact format.
-       ("q-y" (u8vector 64))))
+       (documentation
+       "Public ECC key (always for Curve25519) encoded in a format suitable
+for network transmission and ECDSA signatures.")
+       (field (q-y (u8vector 64))
+             (documentation
+              "Q consists of an x- and a y-value, each mod p (256 bits), given
+here in affine coordinates and Ed25519 standard compact format."))))
 
-    ;; The identity of the host (wraps the signing key of the peer).
-    (define-syntax /peer-identity
+    (define-type /peer-identity
       (structure/packed
-       ("public-key" /eddsa-public-key)))
+       (synopsis
+       "The identity of the host (wraps the signing key of the peer).")
+       (field (public-key /eddsa-public-key))))
 
-    ;; Public ECC key (always for Curve25519) encoded in a format suitable
-    ;; for network transmission and encryption (ECDH),
-    ;; See http://cr.yp.to/ecdh.html
-    (define-syntax /ecdhe-public-key
+    (define-type /ecdhe-public-key
       (structure/packed
-       ;; Q consists of an x- and a y-value, each mod p (256 bits), given
-       ;; here in affine coordinates and Ed25519 standard compact format.
-       ("q-y" (u8vector 64))))
+       (documentation
+       "Public ECC key (always for Curve25519) encoded in a format suitable
+for network transmission and encryption (ECDH),
+See http://cr.yp.to/ecdh.html";)
+       (field (q-y (u8vector 6))
+             (documentation
+              "Q consists of an x- and a y-value, each mod p (256 bits), given
+here in affine coordinates and Ed25519 standard compact format."))))
 
-    ;; Private ECC key encoded for transmission.  To be used only for ECDH
-    ;; key exchange (ECDHE to be precise).
-    (define-syntax /ecdhe-private-key
+    (define-type /ecdhe-private-key
       (structure/packed
-       ;; d is a value mod n, where n has at most 256 bits.
-       ("d" (u8vector 64))))
+       (synopsis "Private ECC key encoded for transmission")
+       (documentation
+       "To be used only for ECDH key exchange (ECDHE to be precise)")
+       (field (d (u8vector 64))
+             (documentation
+              "d is a value mod n, where n has at most 256 bits"))))
 
-    ;; Private ECC key encoded for transmission.  To be used only for ECDSA
-    ;; signatures.
-    (define-syntax /ecdsa-private-key
+    (define-type /ecdsa-private-key
       (structure/packed
-       ;; d is a value mod n, where n has at most 256 bits.
-       ("d" (u8vector 64))))
+       (synopsis "Private ECC key encoded for transmission")
+       (documentation
+       "To be used only for ECDSA signatures.")
+       (field (d (u8vector 64))
+             (documentation
+              "d is a value mod n, where n has at most 256 bits"))))
 
-    ;; Private ECC key encoded for transmission.  To be used only for EdDSA
-    ;; signatures.
-    (define-syntax /eddsa-private-key
+    (define-type /eddsa-private-key
       (structure/packed
-       ;; d is a value mod n, where n has at most 256 bits.
-       ("d" (u8vector 64))))
+       (synopsis "Private ECC key encoded for transmission")
+       (documentation "To be used only for EdDSA signatures.")
+       (field (d (u8vector 64))
+             (documentation
+              "d is a value mod n, where n has at most 256 bits."))))
 
-    ;; type for session keys
-    (define-syntax /symmetric-session-key
+    (define-type /symmetric-session-key
       (structure/packed
-       ;; Actual key for AES.
-       ("aes-key" (u8vector 64))
-       ;; Actual key for TwoFish.
-       ("twofish-key" (u8vector 64))))
+       (synopsis "Type for session keys")
+       (field (aes-key (u8vector 64))
+             (synopsis "Actual key for AES"))
+       (field (twofish-key (u8vector 64))
+             (synopsis "Actual key for TwoFish"))))
 
-    ;; Type of a nonce used for challenges.
-    (define-syntax /challenge-nonce-p
+    (define-type /challenge-nonce-p
       (structure/packed
-       ;; The value of the nonce.  Note that this is NOT a hash.
-       ("value" /hashcode:256)))))
+       (synopsis "Type of a nonce used for challenges")
+       (field (value /hashcode:256)
+             (synopsis
+              "The value of the nonce.  Note that this is NOT a hash."))))))
diff --git a/gnu/gnunet/hashcode/struct.scm b/gnu/gnunet/hashcode/struct.scm
index 3a68dc9..7990e2d 100644
--- a/gnu/gnunet/hashcode/struct.scm
+++ b/gnu/gnunet/hashcode/struct.scm
@@ -19,14 +19,23 @@
 
 ;; Extracted from src/include/gnunet_common.h
 (define-library (gnu gnunet hashcode struct)
-  (export /hashcode:512 hashcode:256)
-  (import (only (rnrs base)
-               begin define-syntax)
-         (gnu gnunet utils netstruct))
+  (export /hashcode:512 /hashcode:256)
+  (import (only (rnrs base) begin)
+         (only (gnu gnunet netstruct syntactic)
+               define-type structure/packed)
+         (only (gnu gnunet netstruct procedural) u8vector))
   (begin
-    ;; A 512-bit hashcode.  These are the default length for GNUnet,
-    ;; using SHA-512.
-    (define-syntax /hashcode:512 (u8vector 64))
-    ;; A 256-bit hashcode.  Used under special conditions, like when space
-    ;; is critical and security is not impacted by it.
-    (define-syntax /hashcode:256 (u8vector 32))))
+    (define-type /hashcode:512
+      (structure/packed
+       (synopsis "A 512-bit hashcode.")
+       (documentation
+       "These are the default length for GNUnet, using SHA-512.")
+       (field (bits/u8 (u8vector 64)))))
+
+    (define-type /hashcode:256
+      (structure/packed
+       (synopsis "A 256-bit hashcode.")
+       (documentation
+       "Used under special conditions, like when space
+is critical and security is not impacted by it.")
+       (field (bits/u8 (u8vector 32)))))))
diff --git a/gnu/gnunet/netstruct/procedural.scm 
b/gnu/gnunet/netstruct/procedural.scm
new file mode 100644
index 0000000..2a38db7
--- /dev/null
+++ b/gnu/gnunet/netstruct/procedural.scm
@@ -0,0 +1,416 @@
+;;   This file is part of scheme-GNUnet, a partial Scheme port of GNUnet.
+;;   Copyright (C) 2020, 2021 Maxime Devos <maximedevos@telenet.be>
+;;
+;;   scheme-GNUnet is free software: you can redistribute it and/or modify it
+;;   under the terms of the GNU Affero General Public License as published
+;;   by the Free Software Foundation, either version 3 of the License,
+;;   or (at your option) any later version.
+;;
+;;   scheme-GNUnet is distributed in the hope that it will be useful, but
+;;   WITHOUT ANY WARRANTY; without even the implied warranty of
+;;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;;   Affero General Public License for more details.
+;;
+;;   You should have received a copy of the GNU Affero General Public License
+;;   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+;;
+;;   SPDX-License-Identifier: AGPL-3.0-or-later
+
+(define-library (gnu gnunet netstruct procedural)
+  (export ;; XXX move elsewhere
+   <documentable> make-documentable documentable?
+   documentation synopsis properties
+
+   netstruct? part sizeof offsetof select read% set%!
+   <netstruct:struct> <netstruct:array> <netstruct:primitive>
+   make-netstructure make-netarray make-netprimitive
+   netstructure? netarray? netprimitive?
+
+   <field> make-field field? field-name field-type
+   netarray-type netarray-length
+
+   &structure-violation
+   &out-of-bounds &no-such-field &unreadable &unwritable
+   &bad-slice-length
+
+   make-structure-violation make-out-of-bounds make-no-such-field
+   make-bad-slice-length make-unreadable make-unwritable
+
+   structure-violation? out-of-bounds? no-such-field?
+   bad-slice-length? unreadable? unwritable?
+
+   bad-slice-length-expected bad-slice-length-found
+
+   u8 u16/big u32/big u64/big
+   u16/little u32/little u64/little
+
+   u8vector
+
+   ;; internal
+   %out-of-bounds/cond %select-length-cond)
+  (import (rnrs base)
+         (rnrs records syntactic)
+         (only (rnrs exceptions) raise)
+         (only (rnrs bytevectors) endianness)
+         (rnrs control)
+         (rnrs conditions)
+         (srfi srfi-26)
+         (only (srfi srfi-43) vector-any)
+         (only (guile) eval-when)
+         (ice-9 optargs)
+         (gnu gnunet utils bv-slice))
+  (begin
+    ;; TODO maybe include structure & field name
+    (define-condition-type &structure-violation &violation
+      make-structure-violation structure-violation?)
+    (define-condition-type &out-of-bounds &structure-violation
+      make-out-of-bounds out-of-bounds?)
+    (define-condition-type &no-such-field &structure-violation
+      make-no-such-field no-such-field?)
+    (define-condition-type &bad-slice-length &structure-violation
+      make-bad-slice-length bad-slice-length?
+      (expected bad-slice-length-expected)
+      (found    bad-slice-length-found))
+    (define-condition-type &unreadable &violation
+      make-unreadable unreadable?)
+    (define-condition-type &unwritable &violation
+      make-unwritable unwritable?)
+
+    ;; TODO also use for enumerations and optionally include line numbers
+    (define-record-type (<documentable> make-documentable documentable?)
+      (fields (immutable documentation documentation)
+             (immutable synopsis synopsis)
+             (immutable properties properties))
+      (sealed #f)
+      (opaque #t)
+      (protocol (lambda (%make)
+                 (lambda* (#:key
+                           (documentation #f)
+                           (synopsis #f)
+                           (properties '())
+                           #:allow-other-keys)
+                 "A synopsis and documentation string can be specified
+with @var{synopsis} and @var{documentation} (two strings).
+@var{properties} can be arbitrary (but usually is an association list)
+and is an empty list by default.  Other keyword arguments are ignored."
+                 (when synopsis
+                   (assert (string? synopsis)))
+                 (when documentation
+                   (assert (string? documentation)))
+                 ;; TODO somehow make properties read-only
+                 ;; (disallow set-car!, set-cdr!)
+                 (%make synopsis documentation properties)))))
+
+    (define-record-type (<netstruct/vtable> make-netstruct-vtable 
netstruct-vtable?)
+      (fields (immutable offset   ~offset)
+             (immutable part     ~part)
+             (immutable reader   ~reader)
+             (immutable setter   ~set))
+      (sealed #f)
+      (opaque #t)
+      (protocol (lambda (%make)
+                 (lambda* (#:key offset part reader setter)
+                   "Make a network structure vtable.  The following
+methods can be defined:
+
+@table @var
+@item offset two-argument procedure, accepts a network structure and a field
+  name and returns the byte offset of the field.
+@item part two-argument procedure, accepts a network structure and a field name
+  and returns the network structure of the field.
+@item reader one-argument procedure, accepts a network structure and returns
+ a procedure accepting a slice.
+@item setter one-argument procedure, accepts a network structure and returns
+ a procedure accepting a slice and a value."
+                   (for-each
+                    (lambda (p)
+                      (when p
+                        (assert (procedure? p))))
+                    (list offset part reader setter))
+                   (%make offset part reader setter)))))
+
+    (define (exact-natural? size)
+      (and (integer? size)
+          (exact? size)
+          (<= 0 size)))
+
+    (define-record-type (<netstruct> %make-netstruct netstruct?)
+      (fields (immutable size %size)
+             (immutable vtable netstruct-vtable))
+      (sealed #f)
+      (opaque #t)
+      (parent <documentable>)
+      (protocol (lambda (%make)
+                 (lambda (size vtable . r)
+                   "Create a network structure.
+
+The size in bytes is specified by @var{size}, a positive and exact integer."
+                   (assert (exact-natural? size))
+                   (assert (netstruct-vtable? vtable))
+                   ((apply %make r) size vtable)))))
+
+    (define (sizeof ns fields)
+      "What is the size of the field @var{fields} of the network structure
+@var{ns} in bytes?"
+      (%size (part ns fields)))
+
+    (define (no-fields who)
+      (raise (condition (make-no-such-field)
+                       (make-who-condition who)
+                       (make-message-condition
+                        "structure does not have any fields"))))
+
+    (define (no-such-field who)
+      (raise (condition (make-no-such-field)
+                       (make-who-condition who)
+                       (make-message-condition
+                        "structure does not have that field"))))
+
+    (define (offsetof ns fields)
+      "What is the offset of the field @var{fields} in the network structure
+@var{ns} in bytes?"
+      (let loop ((off 0) (ns ns) (fields fields))
+       (assert (netstruct? ns))
+       (if (null? fields)
+           off
+           (let* ((field (car fields))
+                  (fields* (cdr fields))
+                  (v (netstruct-vtable ns))
+                  (~part (~part v))
+                  (~offset (~offset v)))
+             (unless (and ~part ~offset)
+               (no-fields 'offsetof))
+             (loop (+ off (~offset ns field))
+                   (~part ns field)
+                   fields*)))))
+
+    (define (part ns fields)
+      "What is the network structure of the field @var{fields} in the
+network structure @var{ns}?"
+      (assert (netstruct? ns))
+      (if (null? fields)
+         ns
+         (let ((field (car fields))
+               (fields* (cdr fields))
+               (~part (~part (netstruct-vtable ns))))
+           (unless ~part (no-fields 'part))
+           (~part ns field))))
+
+    (define (%select-length-cond expected-length found-length)
+      (condition (make-bad-slice-length expected-length found-length)
+                (make-message-condition
+                 "length of bytevector slice is incorrect")
+                (make-who-condition 'select)))
+
+    (define (select ns fields slice)
+      "Select the field @var{fields} of the network structure
+@var{ns} in the bytevector slice @var{ns}.  If the length
+of the slice @var{slice} is inappropriate, raise an appropriate
+exception instead."
+      (let ((expected-length (sizeof ns fields))
+           (found-length    (slice-length slice)))
+       (unless (= found-length expected-length)
+         (raise (%select-length-cond expected-length found-length)))
+       (slice-slice slice (offsetof ns fields) (sizeof ns fields))))
+
+    (define (read% ns fields slice)
+      "Read the field @var{fields} of the network structure @var{ns}
+from the bytevector slice @var{slice}."
+      (let* ((relevant (select ns fields slice))
+            (part (part ns fields))
+            (~reader (~reader (netstruct-vtable part))))
+       (unless ~reader
+         (raise (condition
+                 (make-unreadable)
+                 (make-who-condition 'read%)
+                 (make-message-condition "field cannot be read"))))
+       ((~reader part) slice)))
+
+    (define (set%! ns fields slice value)
+      "Write @var{value} to the field @var{field} of the network
+structure @var{ns} in the bytevector slice @var{ns}."
+      (let* ((relevant (select ns fields slice))
+            (part (part ns fields))
+            (~set (~set (netstruct-vtable part))))
+       (unless ~reader
+         (raise (condition
+                 (make-unreadable)
+                 (make-who-condition 'set%!)
+                 (make-message-condition "field cannot be set"))))
+       ((~set part) slice value)))
+
+    (define-record-type (<field> make-field field?)
+      (fields (immutable name field-name)
+             (immutable type field-type))
+      (parent <documentable>)
+      (protocol (lambda (%make)
+                 (lambda (name type . rest)
+                   "Construct a field with some name
+@var{name} (a symbol) and type @var{type} (a network structure).
+@var{rest} is interpreted the constructor of @code{<documentable>}."
+                   (assert (symbol? name))
+                   (assert (netstruct? type))
+                   ((apply %make rest) name type))))
+      (sealed #f)
+      (opaque #t))
+
+    (define (compute-size fields)
+      (assert (vector? fields))
+      (let loop ((i 0) (size 0))
+       (if (>= i (vector-length fields))
+           size
+           (let* ((field (vector-ref fields i))
+                  (field-size (%size (field-type field))))
+             (loop (+ i 1)
+                   (+ size field-size))))))
+
+    ;; FIXME somehow make the fields vector immutable
+    ;; TODO check for duplicates
+    (define-record-type (<netstruct:struct> make-netstructure netstructure?)
+      (fields (immutable fieldsv %netstruct-fields))
+      (parent <netstruct>)
+      (protocol (lambda (%make)
+                 (lambda (fieldsv . rest)
+                   "Contruct a network struct with fields
+@var{fieldsv}, a vector of field objects."
+                   ((apply %make (compute-size fieldsv) vtable/struct rest)
+                    fieldsv))))
+      (opaque #t)
+      (sealed #f))
+
+    (define vtable/struct
+      (let ()
+       (define (offsetof ns field)
+         (let* ((vec (%netstruct-fields ns))
+                (vlen (vector-length vec)))
+           (let loop ((i 0) (off 0))
+             (unless (> i vlen)
+               (no-such-field 'offsetof))
+             (let* ((field (vector-ref vec i))
+                    (fsize (%size (field-type field))))
+               (if (eq? (field-name field) field)
+                   off
+                   (loop (+ i 1)
+                         (+ off fsize)))))))
+
+       (define (part ns field)
+         (let* ((vec (%netstruct-fields ns)))
+           (or (vector-any (lambda (f)
+                             (eq? (field-name f) field))
+                           vec)
+               (no-such-field 'part))))
+       (make-netstruct-vtable
+        #:offset offsetof
+        #:part part)))
+
+    (define-record-type (<netstruct:array> make-netarray netarray?)
+      (fields (immutable type netarray-type)
+             (immutable length netarray-length))
+      (parent <netstruct>)
+      (protocol (lambda (%make)
+                 (lambda (type length . rest)
+                   "Construct a network array of length @var{length}
+and type @var{type} (a network structure)."
+                   (assert (netstruct? type))
+                   (assert (exact-natural? length))
+                   ((apply %make (* length (%size type)) vtable/array rest)
+                    type length))))
+      (opaque #t)
+      (sealed #f))
+
+    ;; Used from (gnu gnunet netstruct syntactic)
+    (define (%out-of-bounds/cond who)
+      (condition (make-out-of-bounds)
+                (make-who-condition who)
+                (make-message-condition
+                 "index is out of bounds")))
+
+    (define (out-of-bounds who)
+      (raise (%out-of-bounds/cond who)))
+
+    (define vtable/array
+      (let ()
+       (define (offsetof ns field)
+         (assert (exact-natural? field))
+         (if (> field (netarray-length ns))
+             (out-of-bounds 'offsetof))
+         (* field (%size (netarray-type ns))))
+       (define (part ns field)
+         (assert (exact-natural? field))
+         (if (> field (netarray-length ns))
+             (out-of-bounds 'part))
+         (netarray-type ns))
+       (make-netstruct-vtable
+        #:offset offsetof
+        #:part part)))
+
+    (define-record-type (<netstruct:primitive> make-netprimitive netprimitive?)
+      (fields (immutable reader primitive-reader)
+             (immutable setter primitive-setter))
+      (parent <netstruct>)
+      (protocol (lambda (%make)
+                 (lambda (size reader setter . rest)
+                   "Construct a network structure of size @var{size}
+in bytes that can be read with @var{reader} and modified with @var{setter}.
+
+The reader @var{read} is a one-argument procedure accepting a bytevector slice
+of length of size @var{size}.  The writer @var{setter} is a two-argument 
procedure
+accepting a bytevector slice and a value."
+                   (assert (procedure? reader))
+                   (assert (procedure? setter))
+                   (assert (exact-natural? size))
+                   ((apply %make size vtable/primitive rest) reader setter))))
+      (opaque #t)
+      (sealed #f))
+
+    (define vtable/primitive
+      (make-netstruct-vtable
+       #:reader primitive-reader
+       #:setter primitive-setter))
+
+    (define (unsigned-N-bytes length slice-ref slice-set! . rest)
+      (apply make-netprimitive length slice-ref slice-set! rest))
+
+    ;; Not used at run-time, only when expanding,
+    ;; so this doesn't need to end up in the .go.
+    (eval-when (expand)
+      (define-syntax define-unsigned-N-bytes
+       (syntax-rules ()
+         ((_ (length slice-ref slice-set!)
+             (name-big name-little))
+          (begin
+            (define name-big
+              (unsigned-N-bytes
+               length
+               (cute slice-ref <> 0 (endianness big))
+               (cute slice-set! <> 0 (endianness big) <>)
+               #:properties '((endianness . big)
+                              (integer-type . unsigned))))
+            (define name-little
+              (unsigned-N-bytes
+               length
+               (cute slice-ref <> 0 (endianness little))
+               (cute slice-set! <> 0 (endianness little) <>)
+               #:properties '((endianness . little)
+                              (integer-type . unsigned))))))))
+      (define-syntax define-unsigned-N-bytes*
+       (syntax-rules ()
+         ((_ ((length slice-ref slice-set!)
+              (name-big name-little)) ...)
+          (begin
+            (define-unsigned-N-bytes
+              (length slice-ref slice-set!) (name-big name-little))
+            ...)))))
+
+    (define u8 (make-netprimitive 8 slice-u8-ref slice-u8-set!
+                                 #:properties '((integer-type . unsigned))))
+
+    (define-unsigned-N-bytes*
+      ((2 slice-u16-ref slice-u16-set!) (u16/big u16/little))
+      ((4 slice-u32-ref slice-u32-set!) (u32/big u32/little))
+      ((8 slice-u64-ref slice-u64-set!) (u64/big u64/little)))
+
+    (define (u8vector n)
+      "Return a network structure representing an array of bytes,
+of length @var{n}."
+      (make-netarray u8 n))))
diff --git a/gnu/gnunet/netstruct/syntactic.scm 
b/gnu/gnunet/netstruct/syntactic.scm
new file mode 100644
index 0000000..85120a5
--- /dev/null
+++ b/gnu/gnunet/netstruct/syntactic.scm
@@ -0,0 +1,427 @@
+;;   This file is part of scheme-GNUnet, a partial Scheme port of GNUnet.
+;;   Copyright (C) 2020, 2021 Maxime Devos <maximedevos@telenet.be>
+;;
+;;   scheme-GNUnet is free software: you can redistribute it and/or modify it
+;;   under the terms of the GNU Affero General Public License as published
+;;   by the Free Software Foundation, either version 3 of the License,
+;;   or (at your option) any later version.
+;;
+;;   scheme-GNUnet is distributed in the hope that it will be useful, but
+;;   WITHOUT ANY WARRANTY; without even the implied warranty of
+;;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;;   Affero General Public License for more details.
+;;
+;;   You should have received a copy of the GNU Affero General Public License
+;;   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+;;
+;;   SPDX-License-Identifier: AGPL-3.0-or-later
+
+;; Synopsis: a wrapper around (gnu gnunet netstruct procedural) performing
+;; some checks and inlining during expansion.
+(define-library (gnu gnunet netstruct syntactic)
+  (export sizeof offsetof select read% set%!
+         structure/packed define-type)
+  (import (rnrs base)
+         (rnrs control)
+         (only (rnrs exceptions)
+               raise)
+         (only (rnrs bytevectors) endianness)
+         (rnrs syntax-case)
+         (only (guile)
+               display
+               newline
+               compose
+               call-with-prompt abort-to-prompt make-prompt-tag
+               resolve-module module-ref)
+         (only (system syntax) syntax-local-binding)
+         (gnu gnunet utils bv-slice)
+         (only (srfi srfi-1) span assq filter-map concatenate)
+         (only (srfi srfi-2) and-let*)
+         (only (srfi srfi-8) receive)
+         (only (srfi srfi-16) case-lambda)
+         (only (srfi srfi-26) cute)
+         (only (srfi srfi-88) keyword?)
+         (only (ice-9 control) let/ec)
+         (prefix (gnu gnunet netstruct procedural)
+                 p@))
+  (begin
+    
+    (define (syntax->attributes s whom)
+      ;; whom: one of field, structure/packed
+      ;; result: some keyword arguments (KEYWORD . VALUE-SYNTAX)
+      ;;  and some other objects (e.g. FIELD . FIELD-SYNTAX)
+      (map (lambda (s)
+            (syntax-case s (synopsis documentation properties field)
+              ((synopsis a) (cons #:synopsis #'a))
+              ((documentation a) (cons #:documentation #'a))
+              ((properties a) (cons #:properties #'a))
+              ((field (name type) . attr) (and (eq? whom 'structure/packed)
+                                               (symbol? (syntax->datum 
#'name)))
+               `(field ,#''name ,#'type .
+                       ,(syntax->attributes #'attr 'field)))))
+          (syntax-list->list-syntax s)))
+
+    (define (attributes->fields-syntax attr)
+      (define (field-attribute->syntax f)
+       (and (eq? (car f) 'field)
+            #`(p@make-field #,(list-ref f 1)
+                            #,(list-ref f 2)
+                            . #,(attributes->keyword-arguments (cdddr f)))))
+      (filter-map field-attribute->syntax attr))
+
+    (define (attributes->keyword-arguments attr)
+      (define (keyword-attribute->list attr)
+       (and (keyword? (car attr))
+            `(,(car attr) ,(cdr attr))))
+      (concatenate (filter-map keyword-attribute->list attr)))
+
+    (define (syntax-cdr s)
+      (syntax-case s ()
+       ((_ . rest) #'rest)))
+
+    (define-syntax structure/packed
+      (lambda (s)
+       (let* ((attr (syntax->attributes
+                     (syntax-cdr s)
+                     'structure/packed)))
+         #`(p@make-netstructure
+            (vector #,@(attributes->fields-syntax attr))
+            #,@(attributes->keyword-arguments attr)))))
+
+    (define-syntax define-type
+      (syntax-rules ()
+       ((_ name value)
+        (define name value))))
+    
+
+    ;; Analysis of syntax into dynamic and static parts
+    ;;
+    ;;  (static . _): _ is self-evaluating
+    ;;  (dynamic . _): _ must be computed at runtime
+    ;;  (dynamic-tail . _): the list _ must be computed at runtime
+    ;;   (if this exists, this must be the last component)
+    (define (decode-netstruct s type-syntax)
+      "Try to determine the @code{<network-structure>} referred
+to by @var{type-syntax}.  If that fails, just return the syntax
+@var{type-syntax} itself."
+      (let/ec dynamic
+       (unless (identifier? type-syntax)
+         (dynamic #'type-syntax))
+       (receive (binding-type val) (syntax-local-binding type-syntax)
+         (unless (eq? binding-type 'global)
+           (dynamic #'type-syntax))
+         (let ((mod (resolve-module (cdr val) #:ensure #f)))
+           (unless mod
+             (dynamic #'type-syntax))
+           (let ((value (module-ref mod (car val))))
+             (unless (p@netstruct? value)
+               (syntax-violation 'decode-netstruct
+                                 "the subform must refer to a netstruct"
+                                 s type-syntax))
+             value)))))
+
+    (define (syntax-list->list-syntax s)
+      (syntax-case s ()
+       (() '())
+       ((x . r) (cons #'x (syntax-list->list-syntax #'r)))))
+
+    (define (decode-fields fields)
+      "Deterine which parts of @var{fields} are variable and which are
+fixed.  Currently, @code{quote}, @code{quasiquote}, @code{unquote}
+and @code{list} are recognised."
+      (syntax-case fields ()
+       ((q (x ...))
+        (cond ((free-identifier=? #'q #'quote)
+               (apply decode-fields/quote
+                      (syntax-list->list-syntax #'(x ...))))
+              ((free-identifier=? #'q #'quasiquote)
+               (apply decode-fields/quasiquote
+                      (syntax-list->list-syntax #'(x ...))))
+              (#t `((dynamic-tail . ,fields)))))
+       ((l x ...)
+        (cond ((free-identifier=? #'l #'list)
+               (apply decode-fields/list
+                      (syntax-list->list-syntax #'(x ...))))
+              (#t `((dynamic-tail . ,fields)))))
+       (x `((dynamic-tail . ,fields)))))
+
+    (define (decode-fields/quote . components)
+      (map (lambda (s) (cons 'static (syntax->datum s)))
+          components))
+
+    (define (decode-fields/quasiquote . components)
+      (map (lambda (s)
+            (syntax-case s ()
+              ((u x) (free-identifier=? #'u #'unquote)
+               (let ((d (syntax->datum #'x)))
+                 (if (self-evaluating? d)
+                     (cons 'static d)
+                     (cons 'dynamic #'x))))
+              (y (cons 'static (syntax->datum s)))))
+          components))
+
+    (define (decode-fields/list . components)
+      (map (lambda (s)
+            (let ((d (syntax->datum s)))
+              (if (self-evaluating? d)
+                  (cons 'static d)
+                  (cons 'dynamic s))))
+          components))
+
+    (define (self-evaluating? datum)
+      ;; booleans, keywords, etc. can be added as-needed
+      (or (number? datum)
+         (string? datum)
+         (vector? datum)
+         (char? datum)))
+
+    
+
+    ;; Partial evaluation
+    (define (verify-bounds/syntax i length)
+      #`(unless (and (integer? #,i)
+                    (exact? #,i)
+                    (<= 0 #,i)
+                    (< #,i length))
+         (raise (%out-of-bounds-cond 'offset+sizeof/partial-tree))))
+
+    (define (offset+sizeof/partial-tree s ns/syntax ns fields)
+      "Return five values: a syntax that computes the offset,
+a syntax that computes the size, a syntax performing bounds
+checks that were eliminated by the partial evaluation,
+whether @var{ns/syntax} was used, and the network structure
+pointed at by @var{fields} (if known, @code{#f} otherwise).
+
+XXX some side-effects are performed both in offset and size
+syntax"
+      (define (static? field)
+       (eq? (car field) 'static))
+      (receive (static partially-dynamic)
+         (span static? fields)
+       (let ((off (p@offsetof ns static))
+             (p   (p@part ns static)))
+         (if (null? partially-dynamic)
+             (values (datum->syntax s off)
+                     (datum->syntax s (p@sizeof ns static))
+                     #'#t
+                     #f
+                     ns)
+             (case (caar partially-dynamic)
+               ((dynamic-tail) ;; XXX untested
+                (values #`(+ #,(datum->syntax s off)
+                             (p@offsetof
+                              (p@part #,ns/syntax
+                                      #,(cdar partially-dynamic))))
+                        #`(p@sizeof #,ns/syntax #,(cdar partially-dynamic))
+                        #'#t
+                        #t
+                        #f))
+               ((dynamic)
+                (receive (off/tail size/tail check/tail used/tail
+                                   innermost)
+                    (offset+sizeof/partial-tree s 'xxx-unsupported p
+                                                (cdr partially-dynamic))
+                  (cond ((p@netarray? p)
+                         (let* ((element-type (p@netarray-type p))
+                                (element-size (p@sizeof element-type '()))
+                                (length (p@netarray-length p))
+                                (i (cdar partially-dynamic)))
+                           (values #`(+ #,(datum->syntax s off)
+                                        (* #,(datum->syntax s element-size) 
#,i)
+                                        #,off/tail)
+                                   size/tail
+                                   #`(begin #,(verify-bounds/syntax i length)
+                                            #,check/tail)
+                                   used/tail
+                                   innermost)))
+                        (#t (raise 'XXX-unsupported))))))))))
+
+    (define (call-with-variable-binder proc)
+      "Call @var{proc} with a procedure @var{make-variable!} and
+@var{done} in a dynamic environment where @var{make-variable!}
+introduces a variable binding, returning a variable and @var{done}
+returns the first argument to @code{let}.
+
+@var{done} can only be used once.
+
+XXX describe this better."
+      (let ((t (make-prompt-tag)))
+       (define (make-variable! v)
+         (abort-to-prompt t 'v v))
+       (define (done)
+         (abort-to-prompt t))
+       (let loop ((bindings #'())
+                  (next (lambda () (proc make-variable! done))))
+         (call-with-prompt t
+           next
+           (case-lambda
+             ((done)
+              (done bindings))
+             ((use-variable unused value)
+              (let* ((vs (generate-temporaries '(1)))
+                     (v (car vs)))
+                (loop #`((#,v #,value) . #,bindings)
+                      (lambda () (use-variable v))))))))))
+
+    (define (bind-variables fields)
+      "Replace variable parts in @var{fields} by variables,
+to avoid performing side-effects twice.  Two values are
+returned: the first argument to the new @code{let} form,
+and the adjusted @var{fields}."
+      (call-with-variable-binder
+       (lambda (make-variable! done)
+        (define (adjust-field field)
+          (case (car field)
+            ((static) field)
+            ((dynamic) (cons 'dynamic (make-variable! (cdr field))))
+            ((dynamic-tail)
+             (cons 'dynamic-tail (make-variable! (cdr field))))))
+        (let ((fields* (map adjust-field fields)))
+          (values (done) fields*)))))
+
+    
+
+    ;; Various syntax
+    (define (any s type fields proc)
+      (let* ((ns (decode-netstruct s type))
+            (fi (decode-fields fields)))
+       (let*-values
+           (((bindings fields*) (bind-variables fi))
+            ((offset size index-check used-ns innermost-ns)
+             (offset+sizeof/partial-tree s #'type-saved ns fields*)))
+         #`(let (#,@(if used-ns
+                       `(,#`(type-saved #,type))
+                       '())
+                 #,@bindings)
+             #,index-check
+             #,(proc offset size)))))
+
+    (define-syntax sizeof
+      (lambda (s)
+       "A syntax for computing the size of a network structure
+(or one of its fields) at compile time where possible."
+       (syntax-case s ()
+         ((_ type fields)
+          (any s #'type #'fields
+               (lambda (offset size) size))))))
+
+    (define-syntax offsetof
+      (lambda (s)
+       "A syntax for computing the offset of a field in a network
+structure at compile time where possible."
+       (syntax-case s ()
+         ((_ type fields)
+          (any s #'type #'fields
+               (lambda (offset size) offset))))))
+
+    (define (any/slice s type fields slice proc)
+      (let* ((ns (decode-netstruct s type))
+            (fi (decode-fields fields)))
+       (let*-values
+           (((bindings fields*) (bind-variables fi))
+            ((offset/field size/field index-check used-ns innermost-ns)
+             (offset+sizeof/partial-tree s #'type-saved ns fields*))
+            ((_/1 size/all _/2 used-ns/all _/3)
+             (offset+sizeof/partial-tree s #'type-saved ns '())))
+         #`(let ((sl #,slice)
+                 #,@(if (or used-ns used-ns/all)
+                        `(,#`(type-saved #,type))
+                        '())
+                 #,@bindings)
+             #,index-check
+             (let ((expected-length #,size/all)
+                   (found-length (slice-length sl)))
+               (unless (= found-length expected-length)
+                      (raise
+                       (p@%select-length-cond expected-length found-length)))
+               (let ((sl:part (slice-slice sl #,offset/field #,size/field)))
+                 #,(proc #'sl:part innermost-ns)))))))
+
+    (define-syntax select
+      (lambda (s)
+       "A syntax for selecting a part of a bytevector slice,
+with some inlining where possible."
+       (syntax-case s ()
+         ((_ type fields slice)
+          (any/slice s #'type #'fields #'slice
+                     (lambda (sl ns) sl))))))
+
+    
+    ;; Reader and setter
+
+    (define-syntax unsigned-N-bytes-syntax
+      (syntax-rules ()
+       ((_ ((N uN/big uN/little)
+            (slice-N-ref slice-N-set!))
+           ...)
+        (lambda (ns)
+          (and-let* ((_1 (p@netprimitive? ns))
+                     (p (p@properties ns))
+                     (t (assq 'integer-type p))
+                     (_2 (eq? (cdr t) 'unsigned))
+                     (e (assq 'endianness p)))
+            (let ((endian (cdr e))
+                  (size (p@sizeof ns '())))
+              (case size
+                ((N)
+                 (case endian
+                   ((big)
+                    (values #`(cute slice-N-ref <> 0 (endianness big))
+                            #`(cute slice-N-set! <> 0 (endianness big))))
+                   ((little)
+                    (values #`(cute slice-N-ref <> 0 (endianness little))
+                            #`(cute slice-N-set! <> 0 (endianness little))))
+                   (else #f)))
+                ...
+                (else #f))))))))
+
+    (define (reader/writer-syntax ns)
+      (if (eq? ns p@u8)
+         (values #'(cute slice-u8-ref <> 0)
+                 #'(cute slice-u8-set! <> 0))
+         ((unsigned-N-bytes-syntax
+           ((2 u16/big u16/little) (slice-u16-ref slice-u16-set!))
+           ((4 u32/big u32/little) (slice-u32-ref slice-u32-set!))
+           ((8 u64/big u64/little) (slice-u64-ref slice-u64-set!)))
+          ns)))
+
+    (define (reader-syntax ns)
+      (call-with-values (lambda () (reader/writer-syntax ns))
+       (case-lambda
+         ((unused) #f)
+         ((reader writer) reader))))
+
+    (define (writer-syntax ns)
+      (call-with-values (lambda () (reader/writer-syntax ns))
+       (case-lambda
+         ((unused) #f)
+         ((reader writer) writer))))
+
+    (define-syntax read%
+      (lambda (s)
+       "A syntax for reading a part of a bytevector slice,
+with some inlining where possible."
+       (syntax-case s ()
+         ((_ type fields slice)
+          (let/ec not-inlinable
+            (any/slice s #'type #'fields #'slice
+                       (lambda (sl ns)
+                         #`(#,(or (reader-syntax ns)
+                                  (not-inlinable
+                                   #'(p@read% type fields slice)))
+                            #,sl))))))))
+    (define-syntax set%!
+      (lambda (s)
+       "A syntax for writing to a part of a bytevector slice,
+with some inlining where possible."
+       (syntax-case s ()
+         ((_ type fields slice value)
+          (let/ec not-inlinable
+            #`(let ((v value))
+                #,(any/slice
+                   s #'type #'fields #'slice
+                   (lambda (sl ns)
+                     #`(#,(or (writer-syntax ns)
+                              (not-inlinable
+                               #'(p@set%! type fields slice value)))
+                        #,sl)))))))))))
diff --git a/gnu/gnunet/nse/struct.scm b/gnu/gnunet/nse/struct.scm
index 7ecd8c9..53f789d 100644
--- a/gnu/gnunet/nse/struct.scm
+++ b/gnu/gnunet/nse/struct.scm
@@ -26,49 +26,58 @@
 (define-library (gnu gnunet nse struct (0 0))
   (export /:msg:nse:estimate
          /:msg:nse:flood)
-  (import (only (rnrs base)
-               define-syntax begin)
-         (gnu gnunet utils netstruct)
-         (gnu gnunet hashcode struct)
-         (gnu gnunet util struct))
+  (import (only (rnrs base) begin quote)
+         (only (gnu gnunet util struct)
+               /:message-header)
+         (only (gnu gnunet crypto struct)
+               /peer-identity /eddsa-signature)
+         (only (gnu gnunet netstruct syntactic)
+               define-type structure/packed)
+         (only (gnu gnunet netstruct procedural)
+               u32/big u64/big))
   (begin
-    ;; Network size estimate sent from the service
-    ;; to clients.  Contains the current size estimate
-    ;; (or 0 if none has been calculated) and the
-    ;; standard deviation of known estimates.
-    (define-syntax /:msg:nse:estimate
-      (structure/packed
-       ;; Type: msg:nse:estimate
-       ("header" /message-header)
-       ("reserved" u32/big)
-       ("timestamp" /time-absolute)
-       ("size-estimate" ieee-double/big)
-       ("std-deviation" ieee-double/big)))
+    ;; XXX check for mistakes
 
-    ;; Network size estimate reply; sent when "this"
-    ;; peer's timer has run out before receiving a
-    ;; valid reply from another peer.
-    (define-syntax /:msg:nse:flood
+    (define-type /:msg:nse:estimate
       (structure/packed
-       ;; Type: msg:nse:flood
-       ("header" /message-header)
-       ;; Number of hops this message has taken so far.
-       ("hop-count" u32/big)
-       ;; Purpose.
-       ("purpose" /ecc-signature-purpose)
-       ;; The current timestamp value (which all
-       ;; peers should agree on).
-       ("timestamp" /time-absolute)
-       ;; Number of matching bits between the hash
-       ;; of timestamp and the initiator's public
-       ;; key.
-       ;; XXX add to (gnu gnunet util struct)
-       ("matching-bits" u32/big)
-       ;; Public key of the originator.
-       ("origin" /peer-identity)
-       ;; Proof of work, causing leading zeros when hashed with pkey.
-       ("proof-of-work" u64/big)
-       ;; Signature (over range specified in purpose).
-       ("signature" /eddsa-signature)))))
+       (synopsis "Network size estimate sent from the service to clients")
+       (documentation
+       "Contains the current size estimate
+(or 0 if none has been calculated) and the
+standard deviation of known estimates.")
+       (properties '((message-symbol msg:nse:estimate)))
+       (field (header /:message-header))
+       (field (reserved u32/big))
+       (field (timestamp /time-absolute))
+       (field (size-estimate ieee-double/big))
+       (field (std-deviation ieee-double/big))))
 
-    
+    (define-type /:msg:nse:flood
+      (structure/packed
+       (synopsis "Network size estimate reply")
+       (documentation
+       "Sent when \"this\" peer's timer has run out before receiving a
+valid reply from another peer.")
+       (properties '((message-symbol msg:nse:flood)))
+       (field (header /:message-header))
+       (field (hop-count u32/big)
+             (synopsis
+              "Number of hops this message has taken so far"))
+       (field (purpose /ecc-signature-purpose)
+             (synopsis "Purpose"))
+       (field (timestamp /time-absolute)
+             (synopsis "The current timestamp value (which all
+peers should agree on)"))
+       (field (matching-bits u32/big)
+             ;; XXX add to (gnu gnunet util struct)
+             ;; XXX I don't understand the above XXX anymore
+             (synopsis
+              "Number of matching bits between the hash
+of timestamp and the initiator's public key."))
+       (field (origin /peer-identity)
+             (synopsis "Public key of the originator"))
+       (field (proof-of-work u64/big)
+             (synopsis
+              "Proof of work, causing leading zeros when hashed with pkey."))
+       (field (signature /eddsa-signature)
+             (synopsis "Signature (over range specified in purpose)."))))))
diff --git a/gnu/gnunet/util/struct.scm b/gnu/gnunet/util/struct.scm
index 46323af..abec52b 100644
--- a/gnu/gnunet/util/struct.scm
+++ b/gnu/gnunet/util/struct.scm
@@ -20,41 +20,50 @@
 ;; Brief: many network structures, that would otherwise result in very
 ;; small source files if each was put in their own module.
 (define-library (gnu gnunet util struct)
-  (export /:message-header /:operation-result)
-  (import (gnu gnunet utils netstruct)
-         (only (rnrs base) begin define-syntax))
+  (export /uuid
+         /:message-header /:operation-result /async-scope-id)
+  (import (only (gnu gnunet netstruct syntactic)
+               define-type structure/packed)
+         (only (gnu gnunet netstruct procedural)
+               u8vector u16/big u32/big u64/big)
+         (only (rnrs base) begin))
   (begin
-    ; A UUID, a 128 bit random value
-    (define-syntax /uuid
+    (define-type /uuid
       (structure/packed
-       ;; 128 random bits
-       ;;  (This is represented as an array of uint32 in GNUnet)
-       ("value/u8" (u8vector 16))))
+       (synopsis "A UUID, a 128 bit random value")
+       (field (value/u8 (u8vector 16))
+             (synopsis "128 random bits")
+             (documentation
+              "This is represented as an array of uint32 in GNUnet"))))
 
-    ;; Header for all communications.
-    (define-syntax /:message-header
+    (define-type /:message-header
       (structure/packed
-       ;; The length of the struct (in bytes, including the length field 
itself),
-       ;; in big-endian format.
-       ("size" u16/big)
-       ;; The type of the message (GNUNET_MESSAGE_TYPE_XXXX in the C
-       ;; implementation and msg:XXX:YYY:... in the Scheme implementation),
-       ;; in big-endian format.
-       ("type" u16/big)))
+       (synopsis "Header for all communications")
+       (field (size u16/big)
+             (documentation
+              "The length of the struct (in bytes, including the length
+field itself), in big-endian format."))
+       (field (type u16/big)
+             (synopsis "The type of the message")
+             (documentation
+              "The type of the message (GNUNET_MESSAGE_TYPE_XXXX in the C
+implementation and msg:XXX:YYY:... in the Scheme implementation),
+in big-endian format."))))
 
-    ;; Answer from service to client about last operation.
-    ;; Possibly followed by data.
-    (define-syntax /:operation-result
+    (define-type /:operation-result
       (structure/packed
-       ("header" /:message-header)
-       ("reserved" u32/big)
-       ;; Operation ID.
-       ("operation-id" u64/big)
-       ;; Status code for the operation.
-       ("result-code" u64/big)))
+       (synopsis "Answer from service to client about last operation")
+       (documentation "Possibly followed by data")
+       (field (header /:message-header))
+       (field (reserved u32/big))
+       (field (operation-id u64/big)
+             (synopsis "Operation ID"))
+       (field (result-code u64/big)
+             (synopsis "Status code for the operation"))))
 
-    ;; Identifier for an asynchronous execution context.
-    (define-syntax /:async-scope-id
+    (define-type /async-scope-id
       (structure/packed
-       ;; This is represented as an array of uint32_t in GNUnet.
-       ("bits/u8" (u8vector 16))))))
+       (synopsis "Identifier for an asynchronous execution context")
+       (documentation
+       "This is represented as an array of uint32_t in GNUnet.")
+       (field (bits/u8 (u8vector 16)))))))

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]