chia-blockchain/chia/wallet/puzzles/curry.clib
Matt Hauff eab43eb800
Add Chialisp pretty printer to pre-commit (#15008)
* Add chialispp port to pre-commit

* Lint files
2023-05-09 14:46:41 -05:00

136 lines
5.1 KiB
Plaintext

(
;; 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 . ; = `(sha256 1)`
0x9dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2) . ; = `(sha256 1 1)` = `(sha256 1 #q)`
(0x02a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222 . ; = `(concat 2 (sha256 1 #a))`
0x02a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5) ; = `(concat 2 (sha256 1 #c))`
)
)
; 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 (f constant_tree)))
(defun-inline sha256_one_one _noargs (r (f constant_tree)))
(defun-inline two_sha256_one_a_kw _noargs (f (r constant_tree)))
(defun-inline two_sha256_one_c_kw _noargs (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 the macro version that inlines everything and expects varargs parameters.
;; It may be more efficient in some cases.
(defmacro curry_hashes_inline (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)
)
)
)
)
)
;; helper macro
(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)
)
)
)
)
)
)