@@ -32,20 +32,37 @@ module DynamoToStruct {
32
32
33
33
// Identical to ItemToStructured, except that the result does not include any attributes configured as DO_NOTHING\
34
34
// Such attributes are unneeded, as they do not partake in signing nor encryption
35
- function method ItemToStructured2 (item : AttributeMap , actions : Types .AttributeActions) : (ret : Result< TerminalDataMap, Error> )
35
+ function ItemToStructured2 (item : AttributeMap , actions : Types .AttributeActions) : (ret : Result< TerminalDataMap, Error> )
36
36
{
37
- // var m := new DafnyLibraries.MutableMap<AttributeName, StructuredDataTerminal>();
38
- // return MakeError("Not valid attribute names : ");
39
-
40
37
var structuredMap := map k < - item | k ! in actions || actions[k] != DO_NOTHING || ReservedPrefix <= k :: k := AttrToStructured (item[k]);
41
38
MapKeysMatchItems (item);
42
39
MapError (SimplifyMapValue(structuredMap))
43
40
}
41
+ by method {
42
+ var attrNames : seq < AttributeName> := SortedSets. ComputeSetToSequence (item.Keys);
43
+ var m := new DafnyLibraries. MutableMap< AttributeName, StructuredDataTerminal> ();
44
+ SequenceIsSafeBecauseItIsInMemory (attrNames);
45
+ for i : uint64 := 0 to |attrNames| as uint64 {
46
+ var k := attrNames[i];
47
+ if k ! in actions || actions[k] != DO_NOTHING || ReservedPrefix <= k {
48
+ var val := AttrToStructured (item[k]);
49
+ if val. Failure? {
50
+ var result := Failure (E(val.error));
51
+ assume {:axiom} ItemToStructured2 (item, actions) == result;
52
+ return result;
53
+ }
54
+ m. Put (k, val.value);
55
+ }
56
+ }
57
+ var result := Success (m.content());
58
+ assume {:axiom} ItemToStructured2 (item, actions) == result;
59
+ return result;
60
+ }
44
61
45
62
// Identical to StructuredToItem, except that any non encrypted fields in the original are passed through unchanged
46
63
// and only encrypted fields are run through StructuredToAttr
47
64
// This one is used for encryption, and so anything in s but not in orig is also kept
48
- function method StructuredToItemEncrypt (s : TerminalDataMap , orig : AttributeMap , actions : CryptoSchemaMap ) : (ret : Result< AttributeMap, Error> )
65
+ function StructuredToItemEncrypt (s : TerminalDataMap , orig : AttributeMap , actions : CryptoSchemaMap ) : (ret : Result< AttributeMap, Error> )
49
66
{
50
67
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]);
51
68
MapKeysMatchItems (orig);
@@ -57,16 +74,79 @@ module DynamoToStruct {
57
74
58
75
Success (oldMap + newMap)
59
76
}
77
+ by method {
78
+ var attrNames : seq < AttributeName> := SortedSets. ComputeSetToSequence (orig.Keys);
79
+ var m := new DafnyLibraries. MutableMap< AttributeName, AttributeValue> ();
80
+ SequenceIsSafeBecauseItIsInMemory (attrNames);
81
+ for i : uint64 := 0 to |attrNames| as uint64 {
82
+ var k := attrNames[i];
83
+ if ! (ReservedPrefix <= k) {
84
+ if (k in s && k in actions && actions[k] == ENCRYPT_AND_SIGN) {
85
+ var val := StructuredToAttr (s[k]);
86
+ if val. Failure? {
87
+ var result := Failure (E(val.error));
88
+ assume {:axiom} StructuredToItemEncrypt (s, orig, actions) == result;
89
+ return result;
90
+ }
91
+ m. Put (k, val.value);
92
+ } else {
93
+ m. Put (k, orig[k]);
94
+ }
95
+ }
96
+ }
97
+ attrNames := SortedSets. ComputeSetToSequence (s.Keys);
98
+ SequenceIsSafeBecauseItIsInMemory (attrNames);
99
+ for i : uint64 := 0 to |attrNames| as uint64 {
100
+ var k := attrNames[i];
101
+ if k ! in orig {
102
+ var val := StructuredToAttr (s[k]);
103
+ if val. Failure? {
104
+ var result := Failure (E(val.error));
105
+ assume {:axiom} StructuredToItemEncrypt (s, orig, actions) == result;
106
+ return result;
107
+ }
108
+ m. Put (k, val.value);
109
+ }
110
+ }
111
+
112
+ var result := Success (m.content());
113
+ assume {:axiom} StructuredToItemEncrypt (s, orig, actions) == result;
114
+ return result;
115
+ }
60
116
61
117
// Identical to StructuredToItem, except that any non encrypted fields in the original are passed through unchanged
62
118
// and only encrypted fields are run through StructuredToAttr\
63
119
// This one is used for decryption, and so anything in s but not in orig is ignored
64
- function method StructuredToItemDecrypt (s : TerminalDataMap , orig : AttributeMap , actions : CryptoSchemaMap ) : (ret : Result< AttributeMap, Error> )
120
+ function StructuredToItemDecrypt (s : TerminalDataMap , orig : AttributeMap , actions : CryptoSchemaMap ) : (ret : Result< AttributeMap, Error> )
65
121
{
66
122
var ddbMap := map k < - orig | ! (ReservedPrefix <= k) :: k := if (k in s && k in actions && actions[k] == ENCRYPT_AND_SIGN) then StructuredToAttr (s[k]) else Success (orig[k]);
67
123
MapKeysMatchItems (orig);
68
124
MapError (SimplifyMapValue(ddbMap))
69
125
}
126
+ by method {
127
+ var attrNames : seq < AttributeName> := SortedSets. ComputeSetToSequence (orig.Keys);
128
+ var m := new DafnyLibraries. MutableMap< AttributeName, AttributeValue> ();
129
+ SequenceIsSafeBecauseItIsInMemory (attrNames);
130
+ for i : uint64 := 0 to |attrNames| as uint64 {
131
+ var k := attrNames[i];
132
+ if ! (ReservedPrefix <= k) {
133
+ if (k in s && k in actions && actions[k] == ENCRYPT_AND_SIGN) {
134
+ var val := StructuredToAttr (s[k]);
135
+ if val. Failure? {
136
+ var result := Failure (E(val.error));
137
+ assume {:axiom} StructuredToItemDecrypt (s, orig, actions) == result;
138
+ return result;
139
+ }
140
+ m. Put (k, val.value);
141
+ } else {
142
+ m. Put (k, orig[k]);
143
+ }
144
+ }
145
+ }
146
+ var result := Success (m.content());
147
+ assume {:axiom} StructuredToItemDecrypt (s, orig, actions) == result;
148
+ return result;
149
+ }
70
150
71
151
// Convert AttributeMap to StructuredDataMap
72
152
function method {:opaque} ItemToStructured (item : AttributeMap ) : (ret : Result< TerminalDataMap, Error> )
@@ -520,13 +600,15 @@ module DynamoToStruct {
520
600
Success (count + body)
521
601
}
522
602
523
- // Specifying the parent (particularly, as the first parameter),
524
- // along with the corresponding precondition,
525
- // lets Dafny find the correct termination metric.
526
- // See "The Parent Trick" for details: <https://leino.science/papers/krml283.html>.
527
- function method MapAttrToBytes (ghost parent: AttributeValue , m: MapAttributeValue , depth : uint64 ): (ret: Result< seq < uint8> , string > )
603
+ function MapAttrToBytesGhost (parent: AttributeValue , m: MapAttributeValue , depth : uint64 ): (ret: Result< seq < uint8> , string > )
528
604
requires forall k < - m :: m[k] < parent
529
605
requires depth <= MAX_STRUCTURE_DEPTH
606
+ decreases parent, 1
607
+ ensures ret. Success? ==>
608
+ && U32ToBigEndian (|m|). Success?
609
+ && |ret. value| >= LENGTH_LEN
610
+ && (|m| == 0 ==> |ret. value| == LENGTH_LEN)
611
+ && ret. value[0.. LENGTH_LEN] == U32ToBigEndian (|m|). value
530
612
{
531
613
// = specification/dynamodb-encryption-client/ddb-attribute-serialization.md#value-type
532
614
// # Value Type MUST be the [Type ID](#type-id) of the type of [Map Value](#map-value).
@@ -550,6 +632,53 @@ module DynamoToStruct {
550
632
Success (count + body)
551
633
}
552
634
635
+ // Specifying the parent (particularly, as the first parameter),
636
+ // along with the corresponding precondition,
637
+ // lets Dafny find the correct termination metric.
638
+ // See "The Parent Trick" for details: <https://leino.science/papers/krml283.html>.
639
+ function MapAttrToBytes (parent: AttributeValue , m: MapAttributeValue , depth : uint64 ): (ret: Result< seq < uint8> , string > )
640
+ requires forall k < - m :: m[k] < parent
641
+ requires depth <= MAX_STRUCTURE_DEPTH
642
+ decreases parent, 2
643
+ ensures ret. Success? ==>
644
+ && U32ToBigEndian (|m|). Success?
645
+ && |ret. value| >= LENGTH_LEN
646
+ && (|m| == 0 ==> |ret. value| == LENGTH_LEN)
647
+ && ret. value[0.. LENGTH_LEN] == U32ToBigEndian (|m|). value
648
+ {
649
+ MapAttrToBytesGhost (parent, m, depth)
650
+ }
651
+ by method {
652
+ // = specification/dynamodb-encryption-client/ddb-attribute-serialization.md#key-value-pair-entries
653
+ // # Entries in a serialized Map MUST be ordered by key value,
654
+ // # ordered in ascending [UTF-16 binary order](./string-ordering.md#utf-16-binary-order).
655
+ var attrNames := SortedSets. ComputeSetToOrderedSequence2 (m.Keys, CharLess);
656
+ SequenceIsSafeBecauseItIsInMemory (attrNames);
657
+ var len := |attrNames| as uint64;
658
+ var output :- U32ToBigEndian64 (len);
659
+ for i : uint64 := 0 to len {
660
+ var k := attrNames[i];
661
+ var val := AttrToBytes (m[k], true, depth+1);
662
+ if val. Failure? {
663
+ var result := Failure (val.error);
664
+ assume {:axiom} MapAttrToBytesGhost (parent, m, depth) == result;
665
+ return result;
666
+ }
667
+ var data := SerializeMapItem (k, val.value);
668
+ if data. Failure? {
669
+ var result := Failure (data.error);
670
+ assume {:axiom} MapAttrToBytesGhost (parent, m, depth) == result;
671
+ return result;
672
+ }
673
+ output := output + data. value;
674
+ }
675
+
676
+ var result := Success (output);
677
+ assume {:axiom} MapAttrToBytesGhost (parent, m, depth) == result;
678
+ return result;
679
+ }
680
+
681
+
553
682
function method ListAttrToBytes (l: ListAttributeValue , depth : uint64 ): (ret: Result< seq < uint8> , string > )
554
683
requires depth <= MAX_STRUCTURE_DEPTH
555
684
ensures ret. Success? ==>
0 commit comments