Skip to content

Commit a70a569

Browse files
authored
feat: simplify structured encryption (#866)
* feat: simplify structured encryption
1 parent 8f8471a commit a70a569

File tree

95 files changed

+5965
-4165
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

95 files changed

+5965
-4165
lines changed

DynamoDbEncryption/.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@ ImplementationFromDafny.cs
33
TestsFromDafny.cs
44
**/bin
55
**/obj
6+
node_modules
7+
project.properties

DynamoDbEncryption/Makefile

+5
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,8 @@ SERVICE_DEPS_DynamoDbEncryptionTransforms := \
7777

7878
format_net:
7979
pushd runtimes/net && dotnet format DynamoDbEncryption.csproj && popd
80+
81+
polymorph:
82+
export DAFNY_VERSION=4.2
83+
npm i --no-save prettier@3 [email protected]
84+
make polymorph_code_gen PROJECT_DEPENDENCIES=

DynamoDbEncryption/dafny/DynamoDbEncryption/Model/DynamoDbEncryption.smithy

+41-41
Original file line numberDiff line numberDiff line change
@@ -347,8 +347,8 @@ list ConstructorPartList {
347347
//= specification/searchable-encryption/virtual.md#virtual-field-initialization
348348
//= type=implication
349349
//# On initialization of a Virtual Field, the caller MUST provide:
350-
//# * A name -- a string
351-
//# * A list of [Virtual Parts](#virtual-part-initialization)
350+
//# - A name -- a string
351+
//# - A list of [Virtual Parts](#virtual-part-initialization)
352352

353353
@javadoc("The configuration for a Virtual Field. A Virtual Field is a field constructed from parts of other fields for use with beacons, but never itself stored on items.")
354354
structure VirtualField {
@@ -442,8 +442,8 @@ structure GetSuffix {
442442
//= specification/searchable-encryption/virtual.md#getsubstring-transform-initialization
443443
//= type=implication
444444
//# On initialization of a GetSubstring Transform, the caller MUST provide:
445-
//# * low : an integer [position](#position-definition)
446-
//# * high : an integer [position](#position-definition)
445+
//# - low : an integer [position](#position-definition)
446+
//# - high : an integer [position](#position-definition)
447447

448448
// return range of characters, 0-based counting
449449
// low is inclusive, high is exclusive
@@ -464,8 +464,8 @@ structure GetSubstring {
464464
//= specification/searchable-encryption/virtual.md#getsegment-transform-initialization
465465
//= type=implication
466466
//# On initialization of a GetSegment Transform, the caller MUST provide:
467-
//# * split : an character
468-
//# * index : an integer [position](#position-definition)
467+
//# - split : an character
468+
//# - index : an integer [position](#position-definition)
469469

470470
// split string on character, then return one piece.
471471
// 'index' has the same semantics as 'low' in GetSubstring
@@ -482,9 +482,9 @@ structure GetSegment {
482482
//= specification/searchable-encryption/virtual.md#getsegments-transform-initialization
483483
//= type=implication
484484
//# On initialization of a GetSegments Transform, the caller MUST provide:
485-
//# * split : an character
486-
//# * low : an integer [position](#position-definition)
487-
//# * high : an integer [position](#position-definition)
485+
//# - split : an character
486+
//# - low : an integer [position](#position-definition)
487+
//# - high : an integer [position](#position-definition)
488488

489489
// split string on character, then return range of pieces.
490490
// 'low' and 'high' have the same semantics as GetSubstring
@@ -504,14 +504,14 @@ structure GetSegments {
504504
//= specification/searchable-encryption/virtual.md#virtual-transform-initialization
505505
//= type=implication
506506
//# On initialization of a Virtual Transform, the caller MUST provide exactly one of
507-
//# * an [Upper](#upper-transform-initialization) transform
508-
//# * a [Lower](#lower-transform-initialization) transform
509-
//# * an [Insert](#insert-transform-initialization) transform
510-
//# * a [GetPrefix](#getprefix-transform-initialization) transform
511-
//# * a [GetSuffix](#getsuffix-transform-initialization) transform
512-
//# * a [GetSubstring](#getsubstring-transform-initialization) transform
513-
//# * a [GetSegment](#getsegment-transform-initialization) transform
514-
//# * a [GetSegments](#getsegments-transform-initialization) transform
507+
//# - an [Upper](#upper-transform-initialization) transform
508+
//# - a [Lower](#lower-transform-initialization) transform
509+
//# - an [Insert](#insert-transform-initialization) transform
510+
//# - a [GetPrefix](#getprefix-transform-initialization) transform
511+
//# - a [GetSuffix](#getsuffix-transform-initialization) transform
512+
//# - a [GetSubstring](#getsubstring-transform-initialization) transform
513+
//# - a [GetSegment](#getsegment-transform-initialization) transform
514+
//# - a [GetSegments](#getsegments-transform-initialization) transform
515515

516516
union VirtualTransform {
517517
upper: Upper,
@@ -566,10 +566,10 @@ structure SharedSet {
566566
//= type=implication
567567
//# On initialization of a Beacon Style, the caller MUST provide exactly one of
568568
//#
569-
//# * a [PartOnly](#partonly-initialization)
570-
//# * a [Shared](#shared-initialization)
571-
//# * an [AsSet](#asset-initialization)
572-
//# * a [SharedSet](#sharedset-initialization)
569+
//# - a [PartOnly](#partonly-initialization)
570+
//# - a [Shared](#shared-initialization)
571+
//# - an [AsSet](#asset-initialization)
572+
//# - a [SharedSet](#sharedset-initialization)
573573

574574
union BeaconStyle {
575575
partOnly: PartOnly,
@@ -581,8 +581,8 @@ union BeaconStyle {
581581
//= specification/searchable-encryption/beacons.md#encrypted-part-initialization
582582
//= type=implication
583583
//# On initialization of a [encrypted part](#encrypted-part-initialization), the caller MUST provide:
584-
//# * A name -- a string, the name of a standard beacon
585-
//# * A prefix -- a string
584+
//# - A name -- a string, the name of a standard beacon
585+
//# - A prefix -- a string
586586

587587
@javadoc("A part of a Compound Beacon that contains a beacon over encrypted data.")
588588
structure EncryptedPart {
@@ -597,8 +597,8 @@ structure EncryptedPart {
597597
//= specification/searchable-encryption/beacons.md#signed-part-initialization
598598
//= type=implication
599599
//# On initialization of a [signed part](#signed-part-initialization), the caller MUST provide:
600-
//# * A name -- a string
601-
//# * A prefix -- a string
600+
//# - A name -- a string
601+
//# - A prefix -- a string
602602

603603
//= specification/searchable-encryption/beacons.md#signed-part-initialization
604604
//= type=implication
@@ -620,7 +620,7 @@ structure SignedPart {
620620
//= specification/searchable-encryption/beacons.md#constructor-initialization
621621
//= type=implication
622622
//# On initialization of a constructor, the caller MUST provide:
623-
//# * A non-empty list of [Constructor parts](#constructor-part-initialization)
623+
//# - A non-empty list of [Constructor parts](#constructor-part-initialization)
624624

625625
@javadoc("The configuration for a particular Compound Beacon construction.")
626626
structure Constructor {
@@ -632,8 +632,8 @@ structure Constructor {
632632
//= specification/searchable-encryption/beacons.md#constructor-part-initialization
633633
//= type=implication
634634
//# On initialization of a constructor part, the caller MUST provide:
635-
//# * A name -- a string
636-
//# * A required flag -- a boolean
635+
//# - A name -- a string
636+
//# - A required flag -- a boolean
637637

638638
@javadoc("A part of a Compound Becaon Construction.")
639639
structure ConstructorPart {
@@ -648,13 +648,13 @@ structure ConstructorPart {
648648
//= specification/searchable-encryption/beacons.md#standard-beacon-initialization
649649
//= type=implication
650650
//# On initialization of a Standard Beacon, the caller MUST provide:
651-
//# * A name -- a string
652-
//# * A `length` -- a [beacon length](#beacon-length)
651+
//# - A name -- a string
652+
//# - A `length` -- a [beacon length](#beacon-length)
653653

654654
//= specification/searchable-encryption/beacons.md#standard-beacon-initialization
655655
//= type=implication
656656
//# On initialization of a Standard Beacon, the caller MAY provide:
657-
//# * a [terminal location](virtual.md#terminal-location) -- a string
657+
//# - a [terminal location](virtual.md#terminal-location) -- a string
658658

659659
@javadoc("The configuration for a Standard Beacon.")
660660
structure StandardBeacon {
@@ -673,15 +673,15 @@ structure StandardBeacon {
673673
//= specification/searchable-encryption/beacons.md#compound-beacon-initialization
674674
//= type=implication
675675
//# On initialization of a Compound Beacon, the caller MUST provide:
676-
//# * A name -- a string
677-
//# * A split character -- a character
676+
//# - A name -- a string
677+
//# - A split character -- a character
678678

679679
//= specification/searchable-encryption/beacons.md#compound-beacon-initialization
680680
//= type=implication
681681
//# On initialization of a Compound Beacon, the caller MAY provide:
682-
//# * A list of [encrypted parts](#encrypted-part-initialization)
683-
//# * A list of [signed parts](#signed-part-initialization)
684-
//# * A list of constructors
682+
//# - A list of [encrypted parts](#encrypted-part-initialization)
683+
//# - A list of [signed parts](#signed-part-initialization)
684+
//# - A list of constructors
685685

686686
@javadoc("The configuration for a Compound Beacon.")
687687
structure CompoundBeacon {
@@ -740,8 +740,8 @@ structure MultiKeyStore {
740740
//= specification/searchable-encryption/search-config.md#beacon-key-source
741741
//= type=implication
742742
//# On initialization of a Beacon Key Source, the caller MUST provide exactly one of
743-
//# * a [Single Key Store](#single-key-store-initialization)
744-
//# * a [Multi Key Store](#multi-key-store-initialization)
743+
//# - a [Single Key Store](#single-key-store-initialization)
744+
//# - a [Multi Key Store](#multi-key-store-initialization)
745745

746746
union BeaconKeySource {
747747
single : SingleKeyStore,
@@ -791,8 +791,8 @@ structure BeaconVersion {
791791
//= specification/searchable-encryption/search-config.md#initialization
792792
//= type=implication
793793
//# On initialization of the Search Config, the caller MUST provide:
794-
//# - A list of [beacon versions](#beacon-version-initialization)
795-
//# - The [version number](#version-number) of the [beacon versions](#beacon-version) to be used for writing.
794+
//# - A list of [beacon versions](#beacon-version-initialization)
795+
//# - The [version number](#version-number) of the [beacon versions](#beacon-version-initialization) to be used for writing.
796796

797797
@javadoc("The configuration for searchable encryption.")
798798
structure SearchConfig {
@@ -855,7 +855,7 @@ operation CreateDynamoDbEncryptionBranchKeyIdSupplier {
855855

856856
//= specification/dynamodb-encryption-client/ddb-encryption-branch-key-id-supplier.md#input
857857
//= type=implication
858-
//# This operation MUST take in a [DynamoDbKeyBranchKeyIdSupplier](#dynamodb-key-branch-key-id-supplier) as input.
858+
//# This operation MUST take in a [DynamoDbKeyBranchKeyIdSupplier](#dynamodbkeybranchkeyidsupplier) as input.
859859
@javadoc("Inputs for creating a Branch Key Supplier from a DynamoDB Key Branch Key Id Supplier")
860860
structure CreateDynamoDbEncryptionBranchKeyIdSupplierInput {
861861
@required

DynamoDbEncryption/dafny/DynamoDbEncryption/src/ConfigToInfo.dfy

+4-4
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ module SearchConfigToInfo {
4848

4949
//= specification/searchable-encryption/search-config.md#initialization
5050
//= type=implication
51-
//# Initialization MUST fail if the length of the list of [beacon versions](#beacon-version) is not 1.
51+
//# Initialization MUST fail if the length of the list of [beacon versions](#beacon-version-initialization) is not 1.
5252
ensures outer.search.Some? && |outer.search.value.versions| != 1 ==> output.Failure?
5353
{
5454
if outer.search.None? {
@@ -738,7 +738,7 @@ module SearchConfigToInfo {
738738

739739
//= specification/searchable-encryption/beacons.md#initialization-failure
740740
//= type=implication
741-
//# Initialization MUST fail if any [constructor](#constructor) is configured with a field name
741+
//# Initialization MUST fail if any [constructor](#constructor-initialization) is configured with a field name
742742
//# that is not a defined [part](#part).
743743
ensures ret.Success? && 0 < |c| ==>
744744
exists p : CB.BeaconPart | p in parts :: p.getName() == c[0].name
@@ -773,14 +773,14 @@ module SearchConfigToInfo {
773773
ensures ret.Success? ==> |ret.value| == origSize
774774
//= specification/searchable-encryption/beacons.md#initialization-failure
775775
//= type=implication
776-
//# Initialization MUST fail if any [constructor](#constructor) is configured without at least one
776+
//# Initialization MUST fail if any [constructor](#constructor-initialization) is configured without at least one
777777
//# required part.
778778
ensures ret.Success? && 0 < |constructors| ==>
779779
0 < SeqCount((p : ConstructorPart) => p.required, constructors[0].parts)
780780

781781
//= specification/searchable-encryption/beacons.md#initialization-failure
782782
//= type=implication
783-
//# Initialization MUST fail if two [constructors](#constructor) are configured
783+
//# Initialization MUST fail if two [constructors](#constructor-initialization) are configured
784784
//# with the same set of required parts.
785785
ensures ret.Success? && 0 < |constructors| ==>
786786
&& MakeConstructor(constructors[0], parts).Success?

DynamoDbEncryption/dafny/DynamoDbEncryption/src/DynamoToStruct.dfy

+13-47
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,12 @@ module DynamoToStruct {
2121

2222
type Error = AwsCryptographyDbEncryptionSdkDynamoDbTypes.Error
2323

24-
type StructuredDataTerminalType = x : StructuredData | x.content.Terminal? witness *
25-
type TerminalDataMap = map<AttributeName, StructuredDataTerminalType>
24+
type TerminalDataMap = map<AttributeName, StructuredDataTerminal>
2625

2726
// This file exists for these two functions : ItemToStructured and StructuredToItem
2827
// which provide conversion between an AttributeMap and a StructuredDataMap
2928

3029
// Convert AttributeMap to StructuredDataMap
31-
//= specification/dynamodb-encryption-client/ddb-item-conversion.md#convert-ddb-item-to-structured-data
32-
//= type=implication
33-
//# - MUST be a [Structured Data Map](../structured-encryption/structures.md#structured-data-map).
3430
function method {:opaque} ItemToStructured(item : AttributeMap) : (ret : Result<TerminalDataMap, Error>)
3531

3632
//= specification/dynamodb-encryption-client/ddb-item-conversion.md#convert-ddb-item-to-structured-data
@@ -39,30 +35,19 @@ module DynamoToStruct {
3935
//# for each attribute on the DynamoDB Item, and no others.
4036
ensures ret.Success? ==> ret.value.Keys == item.Keys
4137

42-
//= specification/dynamodb-encryption-client/ddb-item-conversion.md#convert-ddb-item-to-structured-data
43-
//= type=implication
44-
//# - MUST NOT have [Structured Data Attributes](../structured-encryption/structures.md#structured-data-attributes).
45-
ensures ret.Success? ==> forall v <- ret.value.Values :: v.content.Terminal?
46-
4738
//= specification/dynamodb-encryption-client/ddb-item-conversion.md#convert-ddb-item-to-structured-data
4839
//= type=implication
4940
//# - The [Terminal Type ID](../structured-encryption/structures.md#terminal-type-id) for each attribute MUST
5041
//# be the [Type ID](./ddb-attribute-serialization.md#type-id) of the [serialization](./ddb-attribute-serialization.md) of this Attribute Value.
51-
ensures ret.Success? ==> forall kv <- ret.value.Items :: kv.1.content.Terminal.typeId == AttrToTypeId(item[kv.0])
52-
53-
//= specification/dynamodb-encryption-client/ddb-item-conversion.md#convert-ddb-item-to-structured-data
54-
//= type=implication
55-
//# - The Structured Data Terminal MUST be located at the top level of the Structured Data,
56-
//# string indexed by the Attribute Name.
57-
ensures ret.Success? ==> forall kv <- ret.value.Items :: kv.0 in ret.value.Keys && ret.value[kv.0].content.Terminal?
42+
ensures ret.Success? ==> forall kv <- ret.value.Items :: kv.1.typeId == AttrToTypeId(item[kv.0])
5843

5944
//= specification/dynamodb-encryption-client/ddb-item-conversion.md#convert-ddb-item-to-structured-data
6045
//= type=implication
6146
//# - The [Terminal Value](../structured-encryption/structures.md#terminal-value) for each attribute MUST
6247
//# be the [Value](./ddb-attribute-serialization.md#type-id) of the [serialization](./ddb-attribute-serialization.md) of this Attribute Value.
6348
ensures ret.Success? ==> forall kv <- ret.value.Items ::
6449
&& TopLevelAttributeToBytes(item[kv.0]).Success?
65-
&& kv.1.content.Terminal.value == TopLevelAttributeToBytes(item[kv.0]).value
50+
&& kv.1.value == TopLevelAttributeToBytes(item[kv.0]).value
6651

6752
{
6853
var structuredMap := map k <- item :: k := AttrToStructured(item[k]);
@@ -71,10 +56,7 @@ module DynamoToStruct {
7156
}
7257

7358
// Convert StructuredDataMap to AttributeMap
74-
//= specification/dynamodb-encryption-client/ddb-item-conversion.md#convert-structured-data-to-ddb-item
75-
//= type=implication
76-
//# - MUST be a [Structured Data Map](../structured-encryption/structures.md#structured-data-map).
77-
function method {:opaque} StructuredToItem(s : StructuredDataMap) : (ret : Result<AttributeMap, Error>)
59+
function method {:opaque} StructuredToItem(s : TerminalDataMap) : (ret : Result<AttributeMap, Error>)
7860
//= specification/dynamodb-encryption-client/ddb-item-conversion.md#convert-structured-data-to-ddb-item
7961
//= type=implication
8062
//# - MUST contain an Attribute for every [Structured Data Terminal](../structured-encryption/structures.md#structured-data-terminal)
@@ -125,12 +107,12 @@ module DynamoToStruct {
125107
}
126108

127109
// Prove round trip. A work in progress
128-
lemma RoundTripFromStructured(s : StructuredData)
129-
ensures StructuredToAttr(s).Success? && s.content.Terminal.typeId == SE.BINARY ==>
110+
lemma RoundTripFromStructured(s : StructuredDataTerminal)
111+
ensures StructuredToAttr(s).Success? && s.typeId == SE.BINARY ==>
130112
&& AttrToStructured(StructuredToAttr(s).value).Success?
131-
ensures StructuredToAttr(s).Success? && s.content.Terminal.typeId == SE.BOOLEAN ==>
113+
ensures StructuredToAttr(s).Success? && s.typeId == SE.BOOLEAN ==>
132114
&& AttrToStructured(StructuredToAttr(s).value).Success?
133-
ensures StructuredToAttr(s).Success? && s.content.Terminal.typeId == SE.NULL ==>
115+
ensures StructuredToAttr(s).Success? && s.typeId == SE.NULL ==>
134116
&& AttrToStructured(StructuredToAttr(s).value).Success?
135117
{
136118
reveal AttrToStructured();
@@ -161,34 +143,18 @@ module DynamoToStruct {
161143
AttrToBytes(a, false)
162144
}
163145

164-
function method {:opaque} AttrToStructured(item : AttributeValue) : (ret : Result<StructuredData, string>)
165-
ensures ret.Success? ==> ret.value.content.Terminal?
166-
ensures ret.Success? ==> ret.value.content.Terminal.typeId == AttrToTypeId(item)
146+
function method {:opaque} AttrToStructured(item : AttributeValue) : (ret : Result<StructuredDataTerminal, string>)
147+
ensures ret.Success? ==> ret.value.typeId == AttrToTypeId(item)
167148
ensures ret.Success? ==>
168149
&& TopLevelAttributeToBytes(item).Success?
169-
&& ret.value.content.Terminal.value == TopLevelAttributeToBytes(item).value
150+
&& ret.value.value == TopLevelAttributeToBytes(item).value
170151
{
171152
var body :- TopLevelAttributeToBytes(item);
172-
Success(StructuredData(content := Terminal(StructuredDataTerminal(value := body, typeId := AttrToTypeId(item))), attributes := None))
153+
Success(StructuredDataTerminal(value := body, typeId := AttrToTypeId(item)))
173154
}
174155

175-
function method {:opaque} StructuredToAttr(s : StructuredData) : (ret : Result<AttributeValue, string>)
176-
//= specification/dynamodb-encryption-client/ddb-item-conversion.md#convert-structured-data-to-ddb-item
177-
//= type=implication
178-
//# - This [Structured Data Map](../structured-encryption/structures.md#structured-data-map),
179-
//# if not empty,
180-
//# MUST only contain [Structured Data Terminals](../structured-encryption/structures.md#structured-data-terminal).
181-
ensures ret.Success? ==> s.content.Terminal?
182-
183-
//= specification/dynamodb-encryption-client/ddb-item-conversion.md#convert-structured-data-to-ddb-item
184-
//= type=implication
185-
//# - MUST NOT have [Structured Data Attributes](../structured-encryption/structures.md#structured-data-attributes).
186-
ensures ret.Success? ==> s.attributes.None?
156+
function method {:opaque} StructuredToAttr(s : StructuredDataTerminal) : (ret : Result<AttributeValue, string>)
187157
{
188-
:- Need(s.attributes.None?, "attributes must be None");
189-
:- Need(s.content.Terminal?, "StructuredData to AttributeValue only works on Terminal data");
190-
191-
var Terminal(s) := s.content;
192158
:- Need(|s.typeId| == 2, "Type ID must be two bytes");
193159
var attrValueAndLength :- BytesToAttr(s.value, s.typeId, false);
194160
:- Need(attrValueAndLength.len == |s.value|, "Mismatch between length of encoded data and length of data");

0 commit comments

Comments
 (0)