Skip to content

Commit

Permalink
Bump clvm and replace ((c P A)) with (a P A). Add some cc fixes p…
Browse files Browse the repository at this point in the history
…rior to audit. (Chia-Network#1133)

* Bump clvm versions and replace `((c P A))` with `(a P A)`. Again.

* Modernize some clvm.

* Fix some comments and naming in `cc.clvm`.

* Prohibit `CREATE_ANNOUNCEMENT` in inner puzzle.

* fix cc.clvm

initial commit for innerpuz announcement test

Co-authored-by: matt <[email protected]>
  • Loading branch information
richardkiss and matt-o-how authored Mar 3, 2021
1 parent bac6e36 commit f79152d
Show file tree
Hide file tree
Showing 41 changed files with 177 additions and 143 deletions.
6 changes: 3 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
"chiavdf==0.15.1", # timelord and vdf verification
"chiabip158==0.19", # bip158-style wallet filters
"chiapos==0.12.45", # proof of space
"clvm==0.9.0",
"clvm_rs==0.1.3", # noqa
"clvm_tools==0.4.1", # noqa
"clvm==0.9.3",
"clvm_rs==0.1.4",
"clvm_tools==0.4.3",
"aiohttp==3.7.4", # HTTP server for full node rpc
"aiosqlite==0.17.0", # asyncio wrapper for sqlite, to store blocks
"bitstring==3.1.7", # Binary data management library
Expand Down
12 changes: 6 additions & 6 deletions src/wallet/chialisp.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def args(*path, p=1):


def eval(code, env=args()):
return sexp(cons(code, env))
return sexp("a", code, env)


def apply(name, argv):
Expand Down Expand Up @@ -68,12 +68,12 @@ def sha256(*argv):


SHA256TREE_PROG = """
((c (q ((c 2 (c 2 (c 3 (q ()))))))
(c (q ((c (i (l 5)
(a (q (a 2 (c 2 (c 3 (q ())))))
(c (q (a (i (l 5)
(q (sha256 (q 2)
((c 2 (c 2 (c 9 (q ())))))
((c 2 (c 2 (c 13 (q ())))))))
(q (sha256 (q 1) 5))) 1))) %s)))
(a 2 (c 2 (c 9 (q ()))))
(a 2 (c 2 (c 13 (q ()))))))
(q (sha256 (q 1) 5))) 1)) %s))
"""


Expand Down
2 changes: 1 addition & 1 deletion src/wallet/puzzles/calculate_synthetic_public_key.clvm.hex
Original file line number Diff line number Diff line change
@@ -1 +1 @@
ff1dff02ffff1effff0bff02ff05808080
ff1dff02ffff1effff0bff02ff05808080
205 changes: 120 additions & 85 deletions src/wallet/puzzles/cc.clvm
Original file line number Diff line number Diff line change
@@ -1,47 +1,74 @@
; Coins locked with this puzzle are spendable ccs.
;
; Choose a list of n inputs (n>=1), I_1, ... I_n.
; Choose a list of n inputs (n>=1), I_1, ... I_n with amounts A_1, ... A_n.
;
; A_k : the amount contributed as available for spending by input I_k
; I_k : the input coins, I_k = (parent_k, puzzle_hash_k, A_k) where A_k is an input "amount".
; L_k : the lock coin created by I_k and consumed by I_{k-1}
; O_k : the amount spent by I_k
; D_k = the "delta" O_k - A_k contribution of coin I_k, ie. how much debt this input accumulates
; S_k : the "running subtotal" of deltas (see below)
; We put them in a ring, so "previous" and "next" have intuitive k-1 and k+1 semantics,
; wrapping so {n} and 0 are the same, ie. all indices are mod n.
;
; Each input I_k has an inner solution that creates 0 or more outputs, with total amount O_k.
; Each coin creates 0 or more coins with total output value O_k.
; Let D_k = the "debt" O_k - A_k contribution of coin I_k, ie. how much debt this input accumulates.
; Some coins may spend more than they contribute and some may spend less, ie. D_k need
; not be zero. That's okay. It's enough for the total of all D_k in the ring to be 0.
;
; All conditions go through a "transformer" that looks for CREATE_COIN conditions
; generated by the inner solution, and wraps the puzzle hash.
; A coin can calculate its own D_k since it can verify A_k (it's hashed into the coin id)
; and it can sum up `CREATE_COIN` conditions for O_k.
;
; Three output conditions are prepended to the list of conditions for each I_k:
; (ASSERT_MY_ID I_k) to ensure that the passed in value for I_k is correct
; (CREATE_COIN L_k 0) to create the lock coin
; (ASSERT_COIN_CONSUMED L_{k+1}) to consume the next coin's lock
; Defines a "subtotal of debts" S_k for each coin as follows:
;
; S_1 = 0
; S_k = S_{k-1} + D_{k-1}
;
; Here's the main trick that shows the ring sums to 0.
; You can prove by induction that S_{k+1} = D_1 + D_2 + ... + D_k.
; But it's a ring, so S_{n+1} is also S_1, which is 0. So D_1 + D_2 + ... + D_k = 0.
; So the total debts must be 0, ie. no coins are created or destroyed.
;
; Each coin's solution includes I_{k-1}, I_k, and I_{k+1} along with proofs that each is a CC.
; Each coin's solution includes S_{k-1}. It calculates D_k = O_k - A_k, and then S_k = S_{k-1} + D_{k-1}
;
; Announcements are used to ensure that each S_k follows the pattern is valid.
; Announcements automatically commit to their own coin id.
; Coin I_k creates an announcement that further commits to I_{k-1} and S_{k-1}.
;
; Coin I_k gets a proof that I_{k+1} is a CC, so it knows it must also create an announcement
; when spent. It checks that I_{k+1} creates an announcement committing to I_k and S_k.
;
; So S_{k+1} is correct iff S_k is correct.
;
; Coins also receive proofs that their neighbors are ccs, ensuring the announcements aren't forgeries, as
; inner puzzles are not allowed to use `CREATE_ANNOUNCEMENT`.
;
; For each k, define the "subtotal at k" S_k as follows:
; S_1 = 0 (it could actually be any value, but 0 is an obvious nice way to start)
; S_{k+1} = S_k + D_k = S_k + O_k - A_k
; In summary, I_k generates an announcement Y_k (for "yell") as follows:
;
; Each input I_k creates a lock output L_k that has commitments to the following values:
; - O_k (calculated from the inner puzzle & inner solution)
; - I_k (passed in by the solution, and verified with ASSERT_MY_ID)
; - I_{k+1} where k+1 wraps around to 1 if k = n (passed in by the solution)
; - S_k (passed in by the solution)
; Y_k: hash of I_k (automatically), I_{k-1}, S_k
;
; We generate a (CREATE_COIN L_k 0) condition, a lock coin with 0 value.
; Each coin ensures that the next coin's announcement is as expected:
; Y_{k+1} : hash of I_{k+1}, I_k, S_{k+1}
;
; The solution will also pass in O_{k+1} and I_{k+2}.
; With this, and knowing S_k, O_k and A_k, we can calculate L_{k+1} and
; generate an (ASSERT_COIN_CONSUMED L_{k+1}) condition.
; TLDR:
; I_k : coins
; A_k : amount coin k contributes
; O_k : amount coin k spend
; D_k : difference/delta that coin k incurs (A - O)
; S_k : subtotal of debts D_1 + D_2 ... + D_k
; Y_k : announcements created by coin k commiting to I_{k-1}, I_k, S_k
;
; All conditions go through a "transformer" that looks for CREATE_COIN conditions
; generated by the inner solution, and wraps the puzzle hash ensuring the output is a cc.
;
; Three output conditions are prepended to the list of conditions for each I_k:
; (ASSERT_MY_ID I_k) to ensure that the passed in value for I_k is correct
; (CREATE_ANNOUNCEMENT I_{k-1} S_k) to create this coin's announcement
; (ASSERT_ANNOUNCEMENT hashed_announcement(Y_{k+1})) to ensure the next coin really is next and
; the relative values of S_k and S_{k+1} are correct
;
; This is all we need to do to ensure ccs exactly balance in the inputs and outputs.
;
; Proof:
; Consider n, k, I_k values, O_k values, S_k and A_k as above.
; For the (CREATE_COIN L_k) and (ASSERT_COIN_CONSUMED L_{k+1}) to match,
; we see that I_k can ensure that is has the correct values for many things,
; including O_{k+1}, A_{k+1}.
; For the (CREATE_ANNOUNCEMENT Y_{k+1}) (created by the next coin)
; and (ASSERT_ANNOUNCEMENT hashed(Y_{k+1})) to match,
; we see that I_k can ensure that is has the correct value for S_{k+1}.
;
; By induction, we see that S_{m+1} = sum(i, 1, m) [O_i - A_i] = sum(i, 1, m) O_i - sum(i, 1, m) A_i
; So S_{n+1} = sum(i, 1, n) O_i - sum(i, 1, n) A_i. But S_{n+1} is actually S_1 = 0,
Expand All @@ -54,25 +81,29 @@
;; GLOSSARY:
;; mod-hash: this code's sha256 tree hash
;; genesis-coin-checker: the function that determines if a coin can mint new ccs
;; inner-puzzle: the puzzle protecting the coins
;; inner-puzzle: an independent puzzle protecting the coins. Solutions to this puzzle are expected to
;; generate `AGG_SIG` conditions and possibly `CREATE_COIN` conditions.
;; ---- items above are curried into the puzzle hash ----
;; inner-puzzle-solution: the solution to the inner puzzle
;; prev-coin-bundle: the bundle for the previous coin
;; my-coin-bundle: the bundle for this coin
;; next-coin-bundle: the bundle for the next coin
;; left-subtotal: the subtotal between prev-coin and this-coin
;; prev-coin-bundle: the bundle for previous coin
;; this-coin-bundle: the bundle for this coin
;; next-coin-bundle: the bundle for next coin
;; prev-subtotal: the subtotal between prev-coin and this-coin
;;
;; A coin bundle is the cons box ((parent_id puzzle_hash amount) . lineage_proof)
;; coin-info: `(parent_id puzzle_hash amount)`. This defines the coin id used with ASSERT_MY_COIN_ID
;; coin-bundle: the cons box `(coin-info . lineage_proof)`
;;
;; and automatically hashed in to the announcement generated with CREATE_ANNOUNCEMENT.
;;

(mod (mod-hash ;; curried into puzzle
genesis-coin-checker ;; curried into puzzle
inner-puzzle ;; curried into puzzle
inner-puzzle-solution ;; if invalid, inner-puzzle will fail
prev-coin-bundle ;; used in this coin's lock coin, prev-coin ASSERT_CONSUMED will fail if wrong
my-coin-bundle ;; verified with ASSERT_MY_COIN_ID
next-coin-bundle ;; used to generate ASSERT_CONSUMED
left-subtotal ;; included in lock, prev-coin ASSERT_CONSUMED will fail if wrong
prev-coin-bundle ;; used in this coin's announcement, prev-coin ASSERT_ANNOUNCEMENT will fail if wrong
this-coin-bundle ;; verified with ASSERT_MY_COIN_ID
next-coin-bundle ;; used to generate ASSERT_ANNOUNCEMENT
prev-subtotal ;; included in announcement, prev-coin ASSERT_ANNOUNCEMENT will fail if wrong
)

;;;;; start library code
Expand Down Expand Up @@ -150,13 +181,17 @@
)

;; tweak `CREATE_COIN` condition by wrapping the puzzle hash, forcing it to be a cc
;; prohibit CREATE_ANNOUNCEMENT
(defun-inline morph-condition (condition lineage-proof-parameters)
(if (= (f condition) CREATE_COIN)
(list CREATE_COIN
(cc-puzzle-hash lineage-proof-parameters (f (r condition)))
(f (r (r condition)))
)
condition
(if (= (f condition) CREATE_ANNOUNCEMENT)
(x)
condition
)
)
)

Expand All @@ -177,34 +212,30 @@
)

;; utility to fetch coin amount from coin
(defun-inline amount-for-coin (coin)
(defun-inline input-amount-for-coin (coin)
(f (r (r coin)))
)

;; calculate the coin id of a lock coin
(defun-inline calculate-next-lock-coin-id (my-coin-info subtotal next-coin-info)
(sha256 (coin-id-for-coin next-coin-info) (puzzle-hash-for-lock my-coin-info subtotal))
;; calculate the hash of an announcement
(defun-inline calculate-annoucement-id (this-coin-info this-subtotal next-coin-info)
; NOTE: the next line containts a bug, as sha256tree1 ignores `this-subtotal`
(sha256 (coin-id-for-coin next-coin-info) (sha256tree1 (list this-coin-info this-subtotal)))
)

;; create the `ASSERT_COIN_CONSUMED` condition that ensures the next coin's lock is spent
(defun-inline create-assert-next-lock-consumed-condition (my-coin-info right-subtotal next-coin-info)
;; create the `ASSERT_ANNOUNCEMENT` condition that ensures the next coin's announcement is correct
(defun-inline create-assert-next-announcement-condition (this-coin-info this-subtotal next-coin-info)
(list ASSERT_ANNOUNCEMENT
(calculate-next-lock-coin-id my-coin-info
right-subtotal
next-coin-info
(calculate-annoucement-id this-coin-info
this-subtotal
next-coin-info
)
)
)

;; calculate the puzzle hash for a lock coin
(defun-inline puzzle-hash-for-lock (prev-coin-info left-subtotal)
(sha256tree1 prev-coin-info left-subtotal)
)

;; here we commit to O_k, I_{k+1} and S_k
(defun-inline create-lock-coin-condition (prev-coin-info subtotal)
;; here we commit to I_{k-1} and S_k
(defun-inline create-announcement-condition (prev-coin-info prev-subtotal)
(list CREATE_ANNOUNCEMENT
(puzzle-hash-for-lock prev-coin-info subtotal)
(sha256tree1 (list prev-coin-info prev-subtotal))
)
)

Expand All @@ -230,27 +261,27 @@
)
)

;; ensure `my-coin-info` is correct by creating the `ASSERT_MY_COIN_ID` condition
(defun-inline create-assert-my-id (my-coin-info)
(list ASSERT_MY_COIN_ID (coin-id-for-coin my-coin-info))
;; ensure `this-coin-info` is correct by creating the `ASSERT_MY_COIN_ID` condition
(defun-inline create-assert-my-id (this-coin-info)
(list ASSERT_MY_COIN_ID (coin-id-for-coin this-coin-info))
)

;; add three conditions to the list of morphed conditions:
;; CREATE_COIN for the lock coin
;; ASSERT_MY_COIN_ID for `my-coin-info`
;; ASSERT_COIN_CONSUMED for the next coin's lock coin
;; ASSERT_MY_COIN_ID for `this-coin-info`
;; CREATE_ANNOUNCEMENT for my announcement
;; ASSERT_ANNOUNCEMENT for the next coin's announcement
(defun-inline generate-final-output-conditions
(
left-subtotal
right-subtotal
prev-subtotal
this-subtotal
morphed-conditions
prev-coin-info
my-coin-info
this-coin-info
next-coin-info
)
(c (create-assert-my-id my-coin-info)
(c (create-lock-coin-condition prev-coin-info left-subtotal)
(c (create-assert-next-lock-consumed-condition my-coin-info right-subtotal next-coin-info)
(c (create-assert-my-id this-coin-info)
(c (create-announcement-condition prev-coin-info prev-subtotal)
(c (create-assert-next-announcement-condition this-coin-info this-subtotal next-coin-info)
morphed-conditions)
)
)
Expand All @@ -262,13 +293,13 @@

;;;;;;;;;;;;;;;;;;;;;;;;;;; lineage checking

;; return true iff parent of `my-coin-info` is provably a cc
;; return true iff parent of `this-coin-info` is provably a cc
(defun is-parent-cc (
lineage-proof-parameters
my-coin-info
this-coin-info
(parent-parent-coin-id parent-inner-puzzle-hash parent-amount)
)
(= (f my-coin-info)
(= (f this-coin-info)
(sha256 parent-parent-coin-id
(cc-puzzle-hash lineage-proof-parameters parent-inner-puzzle-hash)
parent-amount
Expand All @@ -287,12 +318,12 @@
)

(defun-inline is-lineage-proof-valid (
lineage-proof-parameters my-coin-info lineage-proof)
lineage-proof-parameters coin-info lineage-proof)
(if
(f lineage-proof)
(is-parent-cc lineage-proof-parameters my-coin-info (r lineage-proof))
((c (genesis-coin-checker-for-lpp lineage-proof-parameters)
(list lineage-proof-parameters my-coin-info (r lineage-proof))))
(is-parent-cc lineage-proof-parameters coin-info (r lineage-proof))
(a (genesis-coin-checker-for-lpp lineage-proof-parameters)
(list lineage-proof-parameters coin-info (r lineage-proof)))
)
)

Expand All @@ -308,23 +339,27 @@
lineage-proof-parameters
inner-conditions
prev-coin-bundle
my-coin-bundle
this-coin-bundle
next-coin-bundle
left-subtotal
prev-subtotal
)
(assert
; ensure prev is a cc (is this really necessary?)
(is-bundle-valid prev-coin-bundle lineage-proof-parameters)

(is-bundle-valid my-coin-bundle lineage-proof-parameters)
; ensure this is a cc (to ensure parent wasn't counterfeit)
(is-bundle-valid this-coin-bundle lineage-proof-parameters)

; ensure next is a cc (to ensure its announcements can be trusted)
(is-bundle-valid next-coin-bundle lineage-proof-parameters)

(generate-final-output-conditions
left-subtotal
(+ left-subtotal (- (amount-for-coin (coin-info-for-coin-bundle my-coin-bundle)) (output-totals inner-conditions)))
prev-subtotal
; the expression on the next line calculates `this-subtotal` by adding the delta to `prev-subtotal`
(+ prev-subtotal (- (input-amount-for-coin (coin-info-for-coin-bundle this-coin-bundle)) (output-totals inner-conditions)))
(morph-conditions inner-conditions lineage-proof-parameters)
(coin-info-for-coin-bundle prev-coin-bundle)
(coin-info-for-coin-bundle my-coin-bundle)
(coin-info-for-coin-bundle this-coin-bundle)
(coin-info-for-coin-bundle next-coin-bundle)
)
)
Expand All @@ -333,10 +368,10 @@
(main
;; cache some stuff: output conditions, and lineage-proof-parameters
(list mod-hash (sha256tree1 mod-hash) genesis-coin-checker (sha256tree1 genesis-coin-checker))
((c inner-puzzle inner-puzzle-solution))
(a inner-puzzle inner-puzzle-solution)
prev-coin-bundle
my-coin-bundle
this-coin-bundle
next-coin-bundle
left-subtotal
prev-subtotal
)
)
Loading

0 comments on commit f79152d

Please sign in to comment.