Jack Firth writes:

> If I make a symbol with `gensym` (or do anything else that creates a new
> value that's not `eq?` to any other value) in some module, what are the
> absolute upper limits on my ability to use that symbol within the module
> without allowing any other modules to get ahold of the symbol? What do code
> inspectors, namespaces, sandboxes, eval, `unsafe` APIs, the FFI, etc. make
> possible for malicious code in external modules?
>
> Context: I'm exploring a "contract witness" idea whose implementation
> currently relies on the eq?-ness of opaque struct instances for security.
> But I vaguely recall hearing once that the The Only Way To Be Sure when it
> comes to struct encapsulation is to put the definition of a struct inside a
> lambda, otherwise some sort of nebulous "bad things" are possible in
> external code that wants to break the invariants of  a struct type.

Struct inside a function is certainly a way to do it.  You may be
interested in the idea of sealer/unsealer pairs from the object
capability world.  I borrowed the implementation of this from Jonathan
Rees' W7 code.  Consider this waived into the public domain, under CC0,
but also with any potential patents waived under the same terms.

Imagine the ability to make a magical canning kit and a can opener,
where the cans produced can only be opened by the respective can opener.

  ; Create a new sealer / unsealer pair and sealed? predicate
  ; sealer-name is optional and just for debugging help
  (define (new-seal [sealer-name #f])
    (define struct-name
      (if sealer-name
          (string->symbol (string-append "sealed-by-" (symbol->string 
sealer-name)))
          'sealed))
    (define-values (struct:seal seal sealed? seal-ref seal-set!)
      (make-struct-type struct-name #f 1 0))
    (define unseal
      (make-struct-field-accessor seal-ref 0))
    (values seal unseal sealed?))

Now let's try using it:

  (define-values (can-sealer can-unseal can-seal?)
    (new-seal 'canning-factory))

The traditional ocap example is to seal tuna, but I'm vegetarian.

  (define lunch (seal "chickpea salad"))

  lunch ; #<sealed-by-canning-factory>

I'm in control of the sealer from my little canning factory, I don't
give it to anyone else.  Only someone with the matching unsealer can
open this can.  I can safely put it in the fridge.

I can make sure this can is my lunch, in case I forgot:

  (can-sealed? lunch) ; #t

And I can get to its contents:

  (can-unseal lunch) ; "chickpea salad"

Not that this looks a lot like decryption, but with lexical scope only.
It's possible I am okay with someone else opening my objects, in which
case I might give them the can-sealed? predicate and the can-unseal
procedure... then they can open it, but be sure it's from me.  And
with that you can more or less implement signatures.

BTW, you can do powerful stuff with this... here's an example where
you implement digital money:

  http://erights.org/elib/capability/ode/ode-capabilities.html

Here's the same example from that article, written in Racket code:

  (define (make-mint name)
    (define-values (sealer unsealer sealed?)
      (new-seal name))
    (define/contract mint%
      (class/c [make-purse (->m nonnegative-integer? any/c)])
      (class* object% (writable<%>)
        (super-new)
        (define/public (custom-display p)
          (display (format "#<~a mint>" name) p))
        (define/public (custom-write p)
          (custom-display p))

        (define this-mint this)
        (define/public (make-purse balance)
          (define/contract (decr amount)
            (-> (and/c (>=/c 0)
                       (lambda (amt)
                         (<= amt balance)))
                void?)
            (set! balance (- balance amount)))
          (define/contract purse%
            (class/c [get-balance (->m integer?)]
                     [deposit (->m integer? any/c void?)])
            (class* object% (writable<%>)
              (super-new)
  
              (define/public (custom-display p)
                (display (format "#<has ~a ~a bucks>" balance name) p))
              (define/public (custom-write p)
                (custom-display p))

              (define/public (get-balance)
                balance)
              (define/public (sprout)
                (send this-mint make-purse 0))
              (define/public (get-decr)
                (sealer decr))

              (define/public (deposit amount src)
                ((unsealer (send src get-decr)) amount)
                (set! balance (+ balance amount))
                (void))))
          (new purse%))))
    (new mint%))

  (module+ test
    (define carol-mint
      (make-mint 'Carol))
    (define alice-main-purse
      (send carol-mint make-purse 1000))

    (define bob
      (new
       (class object%
         (super-new)
         (define bob-main-purse
           (send carol-mint make-purse 0))
         (define/public (go-on-ride payment)
           (send bob-main-purse deposit 10 payment)
           (displayln "Whee!  You go on a ride!"))
         (define/public (get-balance)
           (send bob-main-purse get-balance)))))

    ;; Set up purse with limited payment amount in it
    (define payment-for-bob
      (send alice-main-purse sprout))
    (send payment-for-bob deposit 10 alice-main-purse))

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to