@@ -12,56 +12,41 @@ module DynamoToStruct {
12
12
import opened StandardLibrary
13
13
import opened StandardLibrary. UInt
14
14
import opened DynamoDbEncryptionUtil
15
- import AwsCryptographyDbEncryptionSdkDynamoDbTypes
15
+ import Types = AwsCryptographyDbEncryptionSdkDynamoDbTypes
16
16
import UTF8
17
17
import SortedSets
18
18
import Seq
19
19
import Norm = DynamoDbNormalizeNumber
20
20
import SE = StructuredEncryptionUtil
21
21
import StandardLibrary. Sequence
22
+ import DafnyLibraries
22
23
23
- type Error = AwsCryptographyDbEncryptionSdkDynamoDbTypes . Error
24
+ type Error = Types . Error
24
25
25
26
type TerminalDataMap = map < AttributeName, StructuredDataTerminal>
26
27
27
- const UINT32_MAX : uint32 := 0xFFFF_FFFF
28
28
29
- // TO BE DONE -- move to StandardLibrary
30
- function method SeqPosToUInt32 (s: seq <uint8 >, pos : uint32 ): (x: uint32)
31
- requires Add32 (4,pos) as int <= |s|
32
- ensures UInt32ToSeq (x) == s[pos.. pos+ 4]
29
+ function method ItemToStructured2 (item : AttributeMap , actions : Types .AttributeActions) : (ret : Result< TerminalDataMap, Error> )
33
30
{
34
- var x0 := s[pos] as uint32 * 0x100_0000;
35
- var x1 := x0 + s[pos+ 1] as uint32 * 0x1_0000;
36
- var x2 := x1 + s[pos+ 2] as uint32 * 0x100;
37
- x2 + s[pos+ 3] as uint32
38
- }
31
+ // var m := new DafnyLibraries.MutableMap<AttributeName, StructuredDataTerminal>();
32
+ // return MakeError("Not valid attribute names : ");
39
33
40
- function method BigEndianPosToU32 (x : seq <uint8 >, pos : uint32 ) : (ret : Result< uint32, string > )
41
- requires |x| < UINT32_MAX as int
42
- {
43
- if |x| as uint32 < Add32 (pos, LENGTH_LEN32) then
44
- Failure ("Length of 4-byte integer was less than 4")
45
- else
46
- Success (SeqPosToUInt32(x, pos))
34
+ var structuredMap := map k < - item | k in actions && actions[k] != DO_NOTHING :: k := AttrToStructured (item[k]);
35
+ MapKeysMatchItems (item);
36
+ MapError (SimplifyMapValue(structuredMap))
47
37
}
48
38
49
- function method {:opaque} Add32 (x : uint32 , y : uint32 ) : (ret : uint32)
50
- ensures x as uint64 + y as uint64 <= UINT32_MAX as uint64
51
- ensures ret == x + y
39
+ function method StructuredToItem2 (s : TerminalDataMap , orig : AttributeMap , actions : Types .AttributeActions) : (ret : Result< AttributeMap, Error> )
52
40
{
53
- var value : uint64 := x as uint64 + y as uint64;
54
- assume {:axiom} value <= UINT32_MAX as uint64;
55
- value as uint32
56
- }
41
+ var ddbMap := map k < - orig :: k := if (k in s && k in actions && actions[k] == ENCRYPT_AND_SIGN) then StructuredToAttr (s[k]) else Success (orig[k]);
42
+ MapKeysMatchItems (orig);
43
+ var oldMap :- MapError (SimplifyMapValue(ddbMap));
57
44
58
- function method {:opaque} Add32_3 (x : uint32 , y : uint32 , z : uint32 ) : (ret : uint32)
59
- ensures x as uint64 + y as uint64 + z as uint64 <= UINT32_MAX as uint64
60
- ensures ret == x + y + z
61
- {
62
- var value : uint64 := x as uint64 + y as uint64 + z as uint64;
63
- assume {:axiom} value <= UINT32_MAX as uint64;
64
- value as uint32
45
+ var ddbMap2 := map k < - s | k ! in orig :: k := StructuredToAttr (s[k]);
46
+ MapKeysMatchItems (s);
47
+ var newMap :- MapError (SimplifyMapValue(ddbMap2));
48
+
49
+ Success (oldMap + newMap)
65
50
}
66
51
67
52
// This file exists for these two functions : ItemToStructured and StructuredToItem
@@ -132,6 +117,46 @@ module DynamoToStruct {
132
117
133
118
// everything past here is to implement those two
134
119
120
+ const UINT32_MAX : uint32 := 0xFFFF_FFFF
121
+
122
+ // TO BE DONE -- move to StandardLibrary
123
+ function method SeqPosToUInt32 (s: seq <uint8 >, pos : uint32 ): (x: uint32)
124
+ requires Add32 (4,pos) as int <= |s|
125
+ ensures UInt32ToSeq (x) == s[pos.. pos+ 4]
126
+ {
127
+ var x0 := s[pos] as uint32 * 0x100_0000;
128
+ var x1 := x0 + s[pos+ 1] as uint32 * 0x1_0000;
129
+ var x2 := x1 + s[pos+ 2] as uint32 * 0x100;
130
+ x2 + s[pos+ 3] as uint32
131
+ }
132
+
133
+ function method BigEndianPosToU32 (x : seq <uint8 >, pos : uint32 ) : (ret : Result< uint32, string > )
134
+ requires |x| < UINT32_MAX as int
135
+ {
136
+ if |x| as uint32 < Add32 (pos, LENGTH_LEN32) then
137
+ Failure ("Length of 4-byte integer was less than 4")
138
+ else
139
+ Success (SeqPosToUInt32(x, pos))
140
+ }
141
+
142
+ function method {:opaque} Add32 (x : uint32 , y : uint32 ) : (ret : uint32)
143
+ ensures x as uint64 + y as uint64 <= UINT32_MAX as uint64
144
+ ensures ret == x + y
145
+ {
146
+ var value : uint64 := x as uint64 + y as uint64;
147
+ assume {:axiom} value <= UINT32_MAX as uint64;
148
+ value as uint32
149
+ }
150
+
151
+ function method {:opaque} Add32_3 (x : uint32 , y : uint32 , z : uint32 ) : (ret : uint32)
152
+ ensures x as uint64 + y as uint64 + z as uint64 <= UINT32_MAX as uint64
153
+ ensures ret == x + y + z
154
+ {
155
+ var value : uint64 := x as uint64 + y as uint64 + z as uint64;
156
+ assume {:axiom} value <= UINT32_MAX as uint64;
157
+ value as uint32
158
+ }
159
+
135
160
function method MakeError< T> (s : string ) : Result< T, Error> {
136
161
Failure (Error.DynamoDbEncryptionException(message := s))
137
162
}
@@ -527,6 +552,7 @@ module DynamoToStruct {
527
552
&& U32ToBigEndian (|l|). Success?
528
553
&& LENGTH_LEN <= |ret. value|
529
554
&& ret. value[.. LENGTH_LEN] == U32ToBigEndian (|l|). value
555
+ decreases l
530
556
{
531
557
var count :- U32ToBigEndian (|l|);
532
558
var body :- CollectList (l, depth);
@@ -675,12 +701,30 @@ module DynamoToStruct {
675
701
// # A List MAY hold any DynamoDB Attribute Value data type,
676
702
// # and MAY hold values of different types.
677
703
704
+ function {:opaque} CollectListGhost (
705
+ listToSerialize : ListAttributeValue ,
706
+ depth : uint32 ,
707
+ serialized : seq <uint8 > := []
708
+ )
709
+ : (ret : Result< seq < uint8> , string > )
710
+ requires depth <= MAX_STRUCTURE_DEPTH
711
+ ensures (ret.Success? && |listToSerialize| == 0) ==> (ret. value == serialized)
712
+ ensures (ret.Success? && |listToSerialize| == 0) ==> (|ret. value| == |serialized|)
713
+ decreases listToSerialize, 1
714
+ {
715
+ if |listToSerialize| == 0 then
716
+ Success (serialized)
717
+ else
718
+ var val :- AttrToBytes (listToSerialize[0], true, depth+1);
719
+ CollectListGhost (listToSerialize[1..], depth, serialized + val)
720
+ }
721
+
678
722
// Can't be {:tailrecursion} because it calls AttrToBytes which might again call CollectList
679
723
// However, we really need this to loop and not recurse.
680
724
// This verifies without the `by method`, but Dafny is too broken to let it verify by method
681
725
// for example, a call to CollectList somehow does not satisfy the decreases clause
682
726
// hence the {:verify false}
683
- function {:opaque} {:verify false } {:axiom} CollectList (
727
+ function {:opaque} CollectList (
684
728
listToSerialize : ListAttributeValue ,
685
729
depth : uint32 ,
686
730
serialized : seq <uint8 > := []
@@ -689,21 +733,26 @@ module DynamoToStruct {
689
733
requires depth <= MAX_STRUCTURE_DEPTH
690
734
ensures (ret.Success? && |listToSerialize| == 0) ==> (ret. value == serialized)
691
735
ensures (ret.Success? && |listToSerialize| == 0) ==> (|ret. value| == |serialized|)
736
+ decreases listToSerialize, 2
692
737
{
693
- if |listToSerialize| == 0 then
694
- Success (serialized)
695
- else
696
- var val :- AttrToBytes (listToSerialize[0], true, depth+1);
697
- CollectList (listToSerialize[1..], depth, serialized + val)
738
+ CollectListGhost (listToSerialize, depth, serialized)
698
739
}
699
740
by method {
741
+ reveal CollectList ();
742
+ reveal CollectListGhost ();
700
743
var result := serialized;
701
744
for i := 0 to |listToSerialize|
702
745
{
703
- var val :- AttrToBytes (listToSerialize[i], true, depth+1);
704
- result := result + val;
746
+ var val := AttrToBytes (listToSerialize[i], true, depth+1);
747
+ if val. Failure? {
748
+ ret := Failure (val.error);
749
+ assume {:axiom} ret == CollectListGhost (listToSerialize, depth, serialized);
750
+ return ;
751
+ }
752
+ result := result + val. value;
705
753
}
706
- return Success (result);
754
+ ret := Success (result);
755
+ assume {:axiom} ret == CollectListGhost (listToSerialize, depth, serialized);
707
756
}
708
757
709
758
function method SerializeMapItem (key : string , value : seq <uint8 >) : (ret : Result< seq < uint8> , string > )
@@ -939,13 +988,39 @@ module DynamoToStruct {
939
988
Success ((nResultList, new_pos))
940
989
}
941
990
991
+ function {:vcs_split_on_every_assert} {:opaque} DeserializeListGhost (
992
+ serialized : seq <uint8 >,
993
+ pos : uint32 ,
994
+ orig_pos : uint32 ,
995
+ remainingCount : uint32 ,
996
+ depth : uint32 ,
997
+ resultList : AttrValueAndLength
998
+ )
999
+ : (ret : Result< AttrValueAndLength, string > )
1000
+ requires |serialized| < UINT32_MAX as int
1001
+ requires pos as int <= |serialized|
1002
+ requires orig_pos <= pos
1003
+ requires depth <= MAX_STRUCTURE_DEPTH
1004
+ requires resultList. val. L?
1005
+ ensures ret. Success? ==> ret. value. val. L?
1006
+ requires pos == Add32 (orig_pos, resultList.len)
1007
+ ensures ret. Success? ==> ret. value. len <= |serialized| as uint32 - orig_pos
1008
+ decreases |serialized| as uint32 - pos, 1
1009
+ {
1010
+ if remainingCount == 0 then
1011
+ Success (resultList)
1012
+ else
1013
+ var (newResultList, npos) :- DeserializeListEntry (serialized, pos, depth, resultList);
1014
+ DeserializeListGhost (serialized, npos, orig_pos, remainingCount - 1, depth, newResultList)
1015
+ }
1016
+
942
1017
// Bytes to List
943
1018
// Can't be {:tailrecursion} because it calls BytesToAttr which might again call DeserializeList
944
1019
// However, we really need this to loop and not recurse.
945
1020
// This verifies without the `by method`, but Dafny is too broken to let it verify by method
946
1021
// for example, a call to DeserializeListEntry somehow does not satisfy the decreases clause
947
1022
// hence the {:verify false}
948
- function {:vcs_split_on_every_assert} {:opaque} {:verify false } DeserializeList (
1023
+ function {:vcs_split_on_every_assert} {:opaque} DeserializeList (
949
1024
serialized : seq <uint8 >,
950
1025
pos : uint32 ,
951
1026
ghost orig_pos : uint32 ,
@@ -962,28 +1037,33 @@ module DynamoToStruct {
962
1037
ensures ret. Success? ==> ret. value. val. L?
963
1038
requires pos == Add32 (orig_pos, resultList.len)
964
1039
ensures ret. Success? ==> ret. value. len <= |serialized| as uint32 - orig_pos
965
- decreases |serialized| as uint32 - pos, 1
1040
+ decreases |serialized| as uint32 - pos, 2
966
1041
{
967
- if remainingCount == 0 then
968
- Success (resultList)
969
- else
970
- var (newResultList, npos) :- DeserializeListEntry (serialized, pos, depth, resultList);
971
- DeserializeList (serialized, npos, orig_pos, remainingCount - 1, depth, newResultList)
1042
+ DeserializeListGhost (serialized, pos, orig_pos, remainingCount, depth, resultList)
972
1043
}
973
1044
by method {
1045
+ reveal DeserializeListGhost ();
1046
+ reveal DeserializeList ();
974
1047
var npos : uint32 := pos;
975
1048
var newResultList := resultList;
976
1049
for i := 0 to remainingCount
977
1050
invariant serialized == old (serialized)
978
1051
invariant newResultList. val. L?
979
1052
invariant npos as int <= |serialized|
980
1053
invariant npos == Add32 (orig_pos, newResultList.len)
1054
+ invariant npos >= pos
981
1055
{
982
- var test :- DeserializeListEntry (serialized, npos, depth, newResultList);
983
- newResultList := test. 0;
984
- npos := test. 1;
1056
+ var test := DeserializeListEntry (serialized, npos, depth, newResultList);
1057
+ if test. Failure? {
1058
+ ret := Failure (test.error);
1059
+ assume {:axiom} ret == DeserializeListGhost (serialized, pos, orig_pos, remainingCount, depth, resultList);
1060
+ return ;
1061
+ }
1062
+ newResultList := test. value. 0;
1063
+ npos := test. value. 1;
985
1064
}
986
1065
ret := Success (newResultList);
1066
+ assume {:axiom} ret == DeserializeListGhost (serialized, pos, orig_pos, remainingCount, depth, resultList);
987
1067
}
988
1068
989
1069
function method {:vcs_split_on_every_assert} DeserializeMapEntry (
@@ -1039,14 +1119,38 @@ module DynamoToStruct {
1039
1119
Success ((newResultMap, pos))
1040
1120
}
1041
1121
1122
+ function {:vcs_split_on_every_assert} {:opaque} DeserializeMapGhost (
1123
+ serialized : seq <uint8 >,
1124
+ pos : uint32 ,
1125
+ orig_pos : uint32 ,
1126
+ remainingCount : uint32 ,
1127
+ depth : uint32 ,
1128
+ resultMap : AttrValueAndLength )
1129
+ : (ret : Result< AttrValueAndLength, string > )
1130
+ requires |serialized| < UINT32_MAX as int
1131
+ requires pos as int <= |serialized|
1132
+ requires orig_pos <= pos
1133
+ requires resultMap. val. M?
1134
+ requires depth <= MAX_STRUCTURE_DEPTH
1135
+ ensures ret. Success? ==> ret. value. val. M?
1136
+ requires pos == Add32 (orig_pos, resultMap.len)
1137
+ ensures ret. Success? ==> ret. value. len <= |serialized| as uint32 - orig_pos
1138
+ decreases |serialized| as uint32 - pos, 1
1139
+ {
1140
+ if remainingCount == 0 then
1141
+ Success (resultMap)
1142
+ else
1143
+ var (newResultMap, npos) :- DeserializeMapEntry (serialized, pos, depth, resultMap);
1144
+ DeserializeMapGhost (serialized, npos, orig_pos, remainingCount - 1, depth, newResultMap)
1145
+ }
1042
1146
1043
1147
// Bytes to Map
1044
1148
// Can't be {:tailrecursion} because it calls BytesToAttr which might again call DeserializeMap
1045
1149
// However, we really need this to loop and not recurse.
1046
1150
// This verifies without the `by method`, but Dafny is too broken to let it verify by method
1047
1151
// for example, a call to DeserializeMapEntry somehow does not satisfy the decreases clause
1048
1152
// hence the {:verify false}
1049
- function {:vcs_split_on_every_assert} {:opaque} {:verify false } DeserializeMap (
1153
+ function {:vcs_split_on_every_assert} {:opaque} DeserializeMap (
1050
1154
serialized : seq <uint8 >,
1051
1155
pos : uint32 ,
1052
1156
ghost orig_pos : uint32 ,
@@ -1062,29 +1166,33 @@ module DynamoToStruct {
1062
1166
ensures ret. Success? ==> ret. value. val. M?
1063
1167
requires pos == Add32 (orig_pos, resultMap.len)
1064
1168
ensures ret. Success? ==> ret. value. len <= |serialized| as uint32 - orig_pos
1065
- decreases |serialized| as uint32 - pos, 1
1169
+ decreases |serialized| as uint32 - pos, 2
1066
1170
{
1067
- if remainingCount == 0 then
1068
- Success (resultMap)
1069
- else
1070
- var (newResultMap, npos) :- DeserializeMapEntry (serialized, pos, depth, resultMap);
1071
- DeserializeMap (serialized, npos, orig_pos, remainingCount - 1, depth, newResultMap)
1072
-
1171
+ DeserializeMapGhost (serialized, pos, orig_pos, remainingCount, depth, resultMap)
1073
1172
}
1074
1173
by method {
1174
+ reveal DeserializeMapGhost ();
1175
+ reveal DeserializeMap ();
1075
1176
var npos : uint32 := pos;
1076
1177
var newResultMap := resultMap;
1077
1178
for i := 0 to remainingCount
1078
1179
invariant serialized == old (serialized)
1079
1180
invariant newResultMap. val. M?
1080
1181
invariant npos as int <= |serialized|
1081
1182
invariant npos == Add32 (orig_pos, newResultMap.len)
1183
+ invariant npos >= pos
1082
1184
{
1083
- var test :- DeserializeMapEntry (serialized, npos, depth, newResultMap);
1084
- newResultMap := test. 0;
1085
- npos := test. 1;
1185
+ var test := DeserializeMapEntry (serialized, npos, depth, newResultMap);
1186
+ if test. Failure? {
1187
+ ret := Failure (test.error);
1188
+ assume {:axiom} ret == DeserializeMapGhost (serialized, pos, orig_pos, remainingCount, depth, resultMap);
1189
+ return ;
1190
+ }
1191
+ newResultMap := test. value. 0;
1192
+ npos := test. value. 1;
1086
1193
}
1087
1194
ret := Success (newResultMap);
1195
+ assume {:axiom} ret == DeserializeMapGhost (serialized, pos, orig_pos, remainingCount, depth, resultMap);
1088
1196
}
1089
1197
1090
1198
// Bytes to AttributeValue
0 commit comments