( ;; The code below is used to calculate of the tree hash of a curried function ;; without actually doing the curry, and using other optimization tricks ;; like unrolling `sha256tree`. (defconstant TWO 2) (defconstant constant-tree (0x4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a 0x9dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2 0x02a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222 0x02a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5)) ; I looked into calculating the values of `constant-tree` because it's pretty easy to code-golf ; out an implementation that produces the values cheaper than just inlining them. The problem is, ; when do we calculate them? If there were a way to calculate it "before main" and include it in ; the globally-accessible constant table, we could do that. But we can't which means to be optimal, ; client code should call the "build table" code once, then pass it around to anyone that wants to ; call `curry` or `curry2`. This is pretty intrusive, so for now we'll just use the existing ; global constant infrastructure, and include it as a fixed table so the tree of four values will ; appear in all code that includes this file, and it will compress better in generators. (defun-inline sha256_one _noargs (f constant-tree)) (defun-inline sha256_one_one _noargs (f (r constant-tree))) (defun-inline two_sha256_one_a_kw _noargs (f (r (r constant-tree)))) (defun-inline two_sha256_one_c_kw _noargs (f (r (r (r constant-tree))))) ;; this returns the sha256 tree hash of expression F = `((q . a1) a2)` (defun hash-expression-F (a1 a2) (sha256 TWO (sha256 TWO (sha256_one_one) a1) (sha256 TWO a2 (sha256_one))) ) ;; Given the tree hash `environment-hash` of an environment tree E ;; and the tree hash `parameter-hash` of a constant parameter P ;; return the tree hash of the tree corresponding to ;; `(c (q . P) E)` ;; This is the new environment tree with the addition parameter P curried in. ;; ;; Note that `(c (q . P) E)` = `(c . ((q . P) . (E . 0)))` (defun-inline update-hash-for-parameter-hash (parameter-hash environment-hash) (sha256 (two_sha256_one_c_kw) (hash-expression-F parameter-hash environment-hash)) ) ;; Given the tree hash `environment-hash` of an environment tree E ;; and the tree hash `mod-hash` of a mod M ;; return the tree hash of the tree corresponding to ;; `(a (q . M) E)` ;; This is the hash of a new function that adopts the new environment E. ;; This is used to build of the tree hash of a curried function. ;; ;; Note that `(a (q . M) E)` = `(a . ((q . M) . (E . 0)))` (defun-inline tree-hash-of-apply (mod-hash environment-hash) (sha256 (two_sha256_one_a_kw) (hash-expression-F mod-hash environment-hash)) ) ;; This function recursively calls `update-hash-for-parameter-hash` (defun calculate-hash-of-curried-parameters (curry-parameter-hashes) (if curry-parameter-hashes (update-hash-for-parameter-hash (f curry-parameter-hashes) (calculate-hash-of-curried-parameters (r curry-parameter-hashes))) (sha256_one_one) ) ) ;; mod-hash: ;; the hash of a puzzle function, ie. a `mod` ;; ;; curry-parameter-hashes: ;; a list of pre-hashed trees representing parameters to be curried into the puzzle. ;; ;; we return the hash of the curried expression ;; (a (q . mod-hash) (c (cp1 (c cp2 (c ... 1)...)))) ;; ;; Note that from a user's perspective the hashes passed in here aren't simply ;; the hashes of the desired parameters, but their treehash representation since ;; that's the form we're assuming they take in the acutal curried program. ;; inline functions that take varargs don't seem to work, so we can't inline `curry` (defun curry_hashes (mod-hash . curry-parameter-hashes) (tree-hash-of-apply mod-hash (calculate-hash-of-curried-parameters curry-parameter-hashes)) ) ;; this is included for future compilers that handle it properly. If you get weird ;; errors using this, it may be your tooling. Use `curry` above instead, or inline manually. (defun-inline curry_hashes_inline (mod-hash . curry-parameter-hashes) (tree-hash-of-apply mod-hash (calculate-hash-of-curried-parameters curry-parameter-hashes)) ) ;; `curry_mod_hashes_inline` takes exactly two parameters rather than varags, and it can be inlined (defun-inline curry_mod_hashes_inline (mod-hash curry-parameter-hashes) (tree-hash-of-apply mod-hash (calculate-hash-of-curried-parameters curry-parameter-hashes)) ) (defmacro curry_mod_hash_with_hashes (mod_hash . curry_parameter_hashes) (qq (sha256 ; apply (two_sha256_one_a_kw) (sha256 TWO ; func (sha256 TWO (sha256_one_one) (unquote mod_hash) ) (sha256 TWO ; args (unquote (c build_pre_hashed_environment curry_parameter_hashes)) (sha256_one) ) ) ) ) ) (defmacro build_pre_hashed_environment curry_parameter_hashes (qq (sha256 (two_sha256_one_c_kw) (sha256 TWO (sha256 TWO (sha256_one_one) (unquote (f curry_parameter_hashes)) ) (sha256 TWO (unquote (if (r curry_parameter_hashes) (c build_pre_hashed_environment (r curry_parameter_hashes)) (q . (sha256_one_one)))) (sha256_one) ) ) ) ) ) )