@@ -639,14 +639,14 @@ static bool antiDos(flags_type checks, const call* stack, const dag_node* dag, s
639
639
* the Simplicity interpreter.
640
640
*/
641
641
typedef struct memBound {
642
+ size_t extraCellsBound [2 ];
642
643
size_t extraUWORDBound [2 ];
643
644
size_t extraFrameBound [2 ]; /* extraStackBound[0] is for TCO off and extraStackBound[1] is for TCO on */
644
645
} memBound ;
645
646
646
647
/* :TODO: Document extraFrameBound in the Tech Report (and implement it in Haskell) */
647
648
/* Given a well-typed dag representing a Simplicity expression, set '*dag_bound' to the memory requirement for evaluation.
648
- * For all 'i', 0 <= 'i' < 'len', compute 'bound[i].extraUWORDBound' and 'bound[i].extraFrameBound'
649
- * for the subexpression denoted by the slice
649
+ * For all 'i', 0 <= 'i' < 'len', compute 'bound[i]' fields for the subexpression denoted by the slice
650
650
*
651
651
* (dag_nodes[i + 1])dag.
652
652
*
@@ -657,7 +657,9 @@ typedef struct memBound {
657
657
* Precondition: NULL != dag_bound
658
658
* dag_node dag[len] and 'dag' is well-typed with 'type_dag'.
659
659
* Postcondition: if the result is 'true'
660
- * then 'max(dag_bound->extraUWORDBound[0], dag_bound->extraUWORDBound[1]) == SIZE_MAX'.
660
+ * then 'max(dag_bound->extraCellsBound[0], dag_bound->extraCellsBound[1]) == SIZE_MAX'.
661
+ * or 'dag_bound->extraCellsBound' characterizes the number of cells needed during evaluation of 'dag';
662
+ * 'max(dag_bound->extraUWORDBound[0], dag_bound->extraUWORDBound[1]) == SIZE_MAX'.
661
663
* or 'dag_bound->extraUWORDBound' characterizes the number of UWORDs needed
662
664
* for the frames allocated during evaluation of 'dag';
663
665
* 'dag_bound->extraFrameBound[0]' bounds the the number of stack frames needed during execution of 'dag';
@@ -676,6 +678,11 @@ static bool computeEvalTCOBound(memBound *dag_bound, const dag_node* dag, const
676
678
case ASSERTL :
677
679
case ASSERTR :
678
680
case CASE :
681
+ bound [i ].extraCellsBound [0 ] = max ( bound [dag [i ].child [0 ]].extraCellsBound [0 ]
682
+ , bound [dag [i ].child [1 ]].extraCellsBound [0 ] );
683
+ bound [i ].extraCellsBound [1 ] = max ( bound [dag [i ].child [0 ]].extraCellsBound [1 ]
684
+ , bound [dag [i ].child [1 ]].extraCellsBound [1 ] );
685
+
679
686
bound [i ].extraUWORDBound [0 ] = max ( bound [dag [i ].child [0 ]].extraUWORDBound [0 ]
680
687
, bound [dag [i ].child [1 ]].extraUWORDBound [0 ] );
681
688
bound [i ].extraUWORDBound [1 ] = max ( bound [dag [i ].child [0 ]].extraUWORDBound [1 ]
@@ -687,13 +694,20 @@ static bool computeEvalTCOBound(memBound *dag_bound, const dag_node* dag, const
687
694
, bound [dag [i ].child [1 ]].extraFrameBound [1 ] );
688
695
break ;
689
696
case DISCONNECT :
690
- /* :TODO: replace this check with a consensus critical limit. */
691
697
if (SIZE_MAX <= type_dag [DISCONNECT_W256A (dag , type_dag , i )].bitSize ||
692
698
SIZE_MAX <= type_dag [DISCONNECT_BC (dag , type_dag , i )].bitSize ) {
693
699
/* 'BITSIZE(WORD256 * A)' or 'BITSIZE(B * C)' has exceeded our limits. */
700
+ bound [i ].extraCellsBound [0 ] = SIZE_MAX ;
701
+ bound [i ].extraCellsBound [1 ] = SIZE_MAX ;
694
702
bound [i ].extraUWORDBound [0 ] = SIZE_MAX ;
695
703
bound [i ].extraUWORDBound [1 ] = SIZE_MAX ;
696
704
} else {
705
+ bound [i ].extraCellsBound [1 ] = type_dag [DISCONNECT_W256A (dag , type_dag , i )].bitSize ;
706
+ bound [i ].extraCellsBound [0 ] = max (
707
+ bounded_add ( type_dag [DISCONNECT_BC (dag , type_dag , i )].bitSize
708
+ , max ( bounded_add (bound [i ].extraCellsBound [1 ], bound [dag [i ].child [0 ]].extraCellsBound [1 ])
709
+ , max (bound [dag [i ].child [0 ]].extraCellsBound [0 ], bound [dag [i ].child [1 ]].extraCellsBound [1 ]))),
710
+ bound [dag [i ].child [1 ]].extraCellsBound [0 ]);
697
711
bound [i ].extraUWORDBound [1 ] = ROUND_UWORD (type_dag [DISCONNECT_W256A (dag , type_dag , i )].bitSize );
698
712
bound [i ].extraUWORDBound [0 ] = max (
699
713
bounded_add (
@@ -707,13 +721,20 @@ static bool computeEvalTCOBound(memBound *dag_bound, const dag_node* dag, const
707
721
bound [i ].extraFrameBound [0 ] = bound [i ].extraFrameBound [1 ] + 1 ;
708
722
break ;
709
723
case COMP :
710
- /* :TODO: replace this check with a consensus critical limit. */
711
724
if (SIZE_MAX <= type_dag [COMP_B (dag , type_dag , i )].bitSize ) {
712
725
/* 'BITSIZE(B)' has exceeded our limits. */
726
+ bound [i ].extraCellsBound [0 ] = SIZE_MAX ;
727
+ bound [i ].extraCellsBound [1 ] = SIZE_MAX ;
713
728
bound [i ].extraUWORDBound [0 ] = SIZE_MAX ;
714
729
bound [i ].extraUWORDBound [1 ] = SIZE_MAX ;
715
730
} else {
716
- size_t scratch = ROUND_UWORD (type_dag [COMP_B (dag , type_dag , i )].bitSize );
731
+ size_t scratch = type_dag [COMP_B (dag , type_dag , i )].bitSize ;
732
+ bound [i ].extraCellsBound [0 ] = max ( bounded_add ( scratch
733
+ , max ( bound [dag [i ].child [0 ]].extraCellsBound [0 ]
734
+ , bound [dag [i ].child [1 ]].extraCellsBound [1 ] ))
735
+ , bound [dag [i ].child [1 ]].extraCellsBound [0 ] );
736
+ bound [i ].extraCellsBound [1 ] = bounded_add (scratch , bound [dag [i ].child [0 ]].extraCellsBound [1 ]);
737
+ scratch = ROUND_UWORD (scratch );
717
738
bound [i ].extraUWORDBound [0 ] = max ( bounded_add ( scratch
718
739
, max ( bound [dag [i ].child [0 ]].extraUWORDBound [0 ]
719
740
, bound [dag [i ].child [1 ]].extraUWORDBound [1 ] ))
@@ -727,6 +748,11 @@ static bool computeEvalTCOBound(memBound *dag_bound, const dag_node* dag, const
727
748
, bound [dag [i ].child [1 ]].extraFrameBound [1 ] );
728
749
break ;
729
750
case PAIR :
751
+ bound [i ].extraCellsBound [0 ] = bound [dag [i ].child [1 ]].extraCellsBound [0 ];
752
+ bound [i ].extraCellsBound [1 ] = max ( bound [dag [i ].child [0 ]].extraCellsBound [0 ]
753
+ , max ( bound [dag [i ].child [0 ]].extraCellsBound [1 ]
754
+ , bound [dag [i ].child [1 ]].extraCellsBound [1 ] ));
755
+
730
756
bound [i ].extraUWORDBound [0 ] = bound [dag [i ].child [1 ]].extraUWORDBound [0 ];
731
757
bound [i ].extraUWORDBound [1 ] = max ( bound [dag [i ].child [0 ]].extraUWORDBound [0 ]
732
758
, max ( bound [dag [i ].child [0 ]].extraUWORDBound [1 ]
@@ -741,6 +767,9 @@ static bool computeEvalTCOBound(memBound *dag_bound, const dag_node* dag, const
741
767
case INJR :
742
768
case TAKE :
743
769
case DROP :
770
+ bound [i ].extraCellsBound [0 ] = bound [dag [i ].child [0 ]].extraCellsBound [0 ];
771
+ bound [i ].extraCellsBound [1 ] = bound [dag [i ].child [0 ]].extraCellsBound [1 ];
772
+
744
773
bound [i ].extraUWORDBound [0 ] = bound [dag [i ].child [0 ]].extraUWORDBound [0 ];
745
774
bound [i ].extraUWORDBound [1 ] = bound [dag [i ].child [0 ]].extraUWORDBound [1 ];
746
775
@@ -753,6 +782,7 @@ static bool computeEvalTCOBound(memBound *dag_bound, const dag_node* dag, const
753
782
case WITNESS :
754
783
case JET :
755
784
case WORD :
785
+ bound [i ].extraCellsBound [0 ] = bound [i ].extraCellsBound [1 ] = 0 ;
756
786
bound [i ].extraUWORDBound [0 ] = bound [i ].extraUWORDBound [1 ] = 0 ;
757
787
bound [i ].extraFrameBound [0 ] = bound [i ].extraFrameBound [1 ] = 0 ;
758
788
}
@@ -794,19 +824,32 @@ bool evalTCOExpression( bool *evalSuccess, flags_type anti_dos_checks, UWORD* ou
794
824
memBound bound ;
795
825
if (!computeEvalTCOBound (& bound , dag , type_dag , len )) return false;
796
826
797
- size_t UWORDBound = bounded_add ( bounded_add (ROUND_UWORD (inputSize ), ROUND_UWORD (outputSize ))
798
- , max (bound .extraUWORDBound [0 ], bound .extraUWORDBound [1 ])
799
- );
800
- size_t frameBound = bound .extraFrameBound [0 ] + 2 ; /* add the initial input and output frames to the count. */
827
+ const size_t cellsBound = bounded_add ( bounded_add (inputSize , outputSize )
828
+ , max (bound .extraCellsBound [0 ], bound .extraCellsBound [1 ])
829
+ );
830
+ const size_t UWORDBound = bounded_add ( bounded_add (ROUND_UWORD (inputSize ), ROUND_UWORD (outputSize ))
831
+ , max (bound .extraUWORDBound [0 ], bound .extraUWORDBound [1 ])
832
+ );
833
+ const size_t frameBound = bound .extraFrameBound [0 ] + 2 ; /* add the initial input and output frames to the count. */
834
+
835
+ static_assert (CELLS_MAX < SIZE_MAX , "CELLS_MAX is too large." );
836
+ if (CELLS_MAX < cellsBound ) {
837
+ /* Cell count exceeds consensus limits. */
838
+ * evalSuccess = false;
839
+ return true;
840
+ }
841
+
801
842
/* frameBound is at most 2*len. */
802
843
static_assert (DAG_LEN_MAX <= SIZE_MAX / 2 , "2*DAG_LEN_MAX does not fit in size_t." );
803
844
assert (frameBound <= 2 * len );
804
845
805
- /* :TODO: add reasonable, consensus critical limits to cells. */
806
- if (SIZE_MAX <= outputSize || SIZE_MAX <= inputSize || SIZE_MAX <= UWORDBound ) {
807
- * evalSuccess = false;
808
- return true;
809
- }
846
+ /* UWORDBound * UWORD_BIT, the number of bits actually allocacted, is at most the cellBound count plus (worse case) padding bits in each frame. */
847
+ static_assert (1 <= UWORD_BIT , "UWORD_BIT is zero." );
848
+ static_assert (2 * DAG_LEN_MAX <= (SIZE_MAX - CELLS_MAX ) / (UWORD_BIT - 1 ), "cellsBound + frameBound*(UWORD_BIT - 1) doesn't fit in size_t." );
849
+ assert (UWORDBound <= (cellsBound + frameBound * (UWORD_BIT - 1 )) / UWORD_BIT );
850
+
851
+ /* UWORDBound, is also at most the cellsBound, with an entire UWORD per cell (the rest of the UWORD being padding). */
852
+ assert (UWORDBound <= cellsBound );
810
853
811
854
/* We use calloc for 'cells' because the frame data must be initialized before we can perform bitwise operations. */
812
855
UWORD * cells = calloc (UWORDBound ? UWORDBound : 1 , sizeof (UWORD ));
0 commit comments