diff --git a/README.md b/README.md
index 09e9b286f..d6c5711bd 100644
--- a/README.md
+++ b/README.md
@@ -3,11 +3,11 @@
 # Decentralized Web Node (DWN) SDK
 
 Code Coverage
-![Statements](https://img.shields.io/badge/statements-94.74%25-brightgreen.svg?style=flat) ![Branches](https://img.shields.io/badge/branches-94.13%25-brightgreen.svg?style=flat) ![Functions](https://img.shields.io/badge/functions-92.48%25-brightgreen.svg?style=flat) ![Lines](https://img.shields.io/badge/lines-94.74%25-brightgreen.svg?style=flat)
+![Statements](https://img.shields.io/badge/statements-94.69%25-brightgreen.svg?style=flat) ![Branches](https://img.shields.io/badge/branches-94.15%25-brightgreen.svg?style=flat) ![Functions](https://img.shields.io/badge/functions-93.15%25-brightgreen.svg?style=flat) ![Lines](https://img.shields.io/badge/lines-94.69%25-brightgreen.svg?style=flat)
 
 ## Introduction
 
-This repository contains a reference implementation of Decentralized Web Node (DWN) as per the [specification](https://identity.foundation/decentralized-web-node/spec/). This specification is in a draft state and very much so a WIP. For the foreseeable future, a lot of the work on DWN will be split across this repo and the repo that houses the specification, which you can find [here](https://github.com/decentralized-identity/decentralized-web-node). The current goal is to produce a beta implementation by March 2023. This won't include all interfaces described in the DWN spec, but will be enough to begin building applications.
+This repository contains a reference implementation of Decentralized Web Node (DWN) as per the [specification](https://identity.foundation/decentralized-web-node/spec/). This specification is in a draft state and very much so a WIP. For the foreseeable future, a lot of the work on DWN will be split across this repo and the repo that houses the specification, which you can find [here](https://github.com/decentralized-identity/decentralized-web-node). The current implementation does not include all interfaces described in the DWN spec, but is enough to begin building test applications.
 
 This project is used as a dependency by several other projects.
 
diff --git a/src/core/dwn-error.ts b/src/core/dwn-error.ts
index e5d599212..364e954e5 100644
--- a/src/core/dwn-error.ts
+++ b/src/core/dwn-error.ts
@@ -29,10 +29,10 @@ export enum DwnErrorCode {
   RecordsProtocolsDerivationSchemeMissingProtocol = 'RecordsProtocolsDerivationSchemeMissingProtocol',
   RecordsSchemasDerivationSchemeMissingSchema = 'RecordsSchemasDerivationSchemeMissingSchema',
   RecordsWriteGetEntryIdUndefinedAuthor = 'RecordsWriteGetEntryIdUndefinedAuthor',
+  RecordsWriteMissingDataStream = 'RecordsWriteMissingDataStream',
   RecordsWriteValidateIntegrityEncryptionCidMismatch = 'RecordsWriteValidateIntegrityEncryptionCidMismatch',
   Secp256k1KeyNotValid = 'Secp256k1KeyNotValid',
   StorageControllerDataCidMismatch = 'StorageControllerDataCidMismatch',
-  StorageControllerDataNotFound = 'StorageControllerDataNotFound',
   StorageControllerDataSizeMismatch = 'StorageControllerDataSizeMismatch',
   UrlProtocolNotNormalized = 'UrlProtocolNotNormalized',
   UrlProtocolNotNormalizable = 'UrlProtocolNotNormalizable',
diff --git a/src/interfaces/records/handlers/pruned-initial-records-write.ts b/src/interfaces/records/handlers/pruned-initial-records-write.ts
index 864b629d3..9055d5522 100644
--- a/src/interfaces/records/handlers/pruned-initial-records-write.ts
+++ b/src/interfaces/records/handlers/pruned-initial-records-write.ts
@@ -1,7 +1,7 @@
-import type { BaseMessage } from '../../../core/types.js';
 import type { EventLog } from '../../../event-log/event-log.js';
 import type { Readable } from 'readable-stream';
-import type { DataStore, MessageStore } from '../../../index.js';
+import type { BaseMessage, TimestampedMessage } from '../../../core/types.js';
+import type { DataStore, MessageStore, RecordsWriteMessage } from '../../../index.js';
 
 import { Message } from '../../../core/message.js';
 import { RecordsWriteHandler } from './records-write.js';
@@ -11,11 +11,19 @@ import { RecordsWriteHandler } from './records-write.js';
  * NOTE: This is intended to be ONLY used by sync.
  */
 export class PrunedInitialRecordsWriteHandler extends RecordsWriteHandler {
+  /**
+   * Overriding parent behavior, `undefined` data stream is allowed.
+   */
+  protected validateUndefinedDataStream(
+    _dataStream: Readable | undefined,
+    _newestExistingMessage: TimestampedMessage | undefined,
+    _incomingMessage: RecordsWriteMessage): void { }
+
   /**
    * Stores the given message without storing the associated data.
    * Requires `dataCid` to exist in the `RecordsWrite` message given.
    */
-  public async storeMessage(
+  protected async storeMessage(
     messageStore: MessageStore,
     _dataStore: DataStore,
     eventLog: EventLog,
diff --git a/src/interfaces/records/handlers/records-write.ts b/src/interfaces/records/handlers/records-write.ts
index aa16e604c..0889dd9cc 100644
--- a/src/interfaces/records/handlers/records-write.ts
+++ b/src/interfaces/records/handlers/records-write.ts
@@ -7,11 +7,11 @@ import type { DataStore, DidResolver, MessageStore } from '../../../index.js';
 
 import { authenticate } from '../../../core/auth.js';
 import { deleteAllOlderMessagesButKeepInitialWrite } from '../records-interface.js';
-import { DwnErrorCode } from '../../../core/dwn-error.js';
-import { DwnInterfaceName } from '../../../core/message.js';
 import { MessageReply } from '../../../core/message-reply.js';
 import { RecordsWrite } from '../messages/records-write.js';
 import { StorageController } from '../../../store/storage-controller.js';
+import { DwnError, DwnErrorCode } from '../../../core/dwn-error.js';
+import { DwnInterfaceName, Message } from '../../../core/message.js';
 
 export class RecordsWriteHandler implements MethodHandler {
 
@@ -56,54 +56,72 @@ export class RecordsWriteHandler implements MethodHandler {
       }
     }
 
-    // find which message is the newest, and if the incoming message is the newest
-    const newestExistingMessage = await RecordsWrite.getNewestMessage(existingMessages);
+    const newestExistingMessage = await Message.getNewestMessage(existingMessages);
 
     let incomingMessageIsNewest = false;
-    let newestMessage;
-    // if incoming message is newest
-    if (newestExistingMessage === undefined || await RecordsWrite.isNewer(message, newestExistingMessage)) {
+    let newestMessage; // keep reference of newest message for pruning later
+    if (newestExistingMessage === undefined || await Message.isNewer(message, newestExistingMessage)) {
       incomingMessageIsNewest = true;
       newestMessage = message;
     } else { // existing message is the same age or newer than the incoming message
       newestMessage = newestExistingMessage;
     }
 
-    // write the incoming message to DB if incoming message is newest
-    let messageReply: MessageReply;
-    if (incomingMessageIsNewest) {
-      const isLatestBaseState = true;
-      const indexes = await constructRecordsWriteIndexes(recordsWrite, isLatestBaseState);
+    if (!incomingMessageIsNewest) {
+      return new MessageReply({
+        status: { code: 409, detail: 'Conflict' }
+      });
+    }
 
-      try {
-        await this.storeMessage(this.messageStore, this.dataStore, this.eventLog, tenant, message, indexes, dataStream);
-      } catch (error) {
-        const e = error as any;
-        if (e.code === DwnErrorCode.StorageControllerDataCidMismatch ||
-            e.code === DwnErrorCode.StorageControllerDataNotFound ||
-            e.code === DwnErrorCode.StorageControllerDataSizeMismatch) {
-          return MessageReply.fromError(error, 400);
-        }
-
-        // else throw
-        throw error;
+    const isLatestBaseState = true;
+    const indexes = await constructRecordsWriteIndexes(recordsWrite, isLatestBaseState);
+
+    try {
+      this.validateUndefinedDataStream(dataStream, newestExistingMessage, message);
+
+      await this.storeMessage(this.messageStore, this.dataStore, this.eventLog, tenant, message, indexes, dataStream);
+    } catch (error) {
+      const e = error as any;
+      if (e.code === DwnErrorCode.StorageControllerDataCidMismatch ||
+          e.code === DwnErrorCode.StorageControllerDataSizeMismatch ||
+          e.code === DwnErrorCode.RecordsWriteMissingDataStream) {
+        return MessageReply.fromError(error, 400);
       }
 
-      messageReply = new MessageReply({
-        status: { code: 202, detail: 'Accepted' }
-      });
-    } else {
-      messageReply = new MessageReply({
-        status: { code: 409, detail: 'Conflict' }
-      });
+      // else throw
+      throw error;
     }
 
+    const messageReply = new MessageReply({
+      status: { code: 202, detail: 'Accepted' }
+    });
+
     // delete all existing messages that are not newest, except for the initial write
     await deleteAllOlderMessagesButKeepInitialWrite(tenant, existingMessages, newestMessage, this.messageStore, this.dataStore, this.eventLog);
 
     return messageReply;
   };
 
+  /**
+   * Further validation if data stream is undefined.
+   * NOTE: if data stream is not be provided but `dataCid` is provided,
+   * then we need to make sure that the existing record state is referencing the same data as the incoming message.
+   * Without this check will lead to unauthorized access of data (https://github.com/TBD54566975/dwn-sdk-js/issues/359)
+   */
+  protected validateUndefinedDataStream(
+    dataStream: _Readable.Readable | undefined,
+    newestExistingMessage: TimestampedMessage | undefined,
+    incomingMessage: RecordsWriteMessage): void {
+    if (dataStream === undefined && incomingMessage.descriptor.dataCid !== undefined) {
+      if (newestExistingMessage?.descriptor.dataCid !== incomingMessage.descriptor.dataCid) {
+        throw new DwnError(
+          DwnErrorCode.RecordsWriteMissingDataStream,
+          'Data stream is not provided.'
+        );
+      }
+    }
+  }
+
   /**
    * Stores the given message and its data in the underlying database(s).
    * NOTE: this method was created to allow a child class to override the default behavior for sync feature to work:
@@ -111,7 +129,7 @@ export class RecordsWriteHandler implements MethodHandler {
    * a `RecordsDelete` has happened, as a result a DWN would have pruned the data associated with the original write.
    * This approach avoids the need to duplicate the entire handler.
    */
-  public async storeMessage(
+  protected async storeMessage(
     messageStore: MessageStore,
     dataStore: DataStore,
     eventLog: EventLog,
diff --git a/src/store/storage-controller.ts b/src/store/storage-controller.ts
index 980fe21a5..98f8a8316 100644
--- a/src/store/storage-controller.ts
+++ b/src/store/storage-controller.ts
@@ -18,8 +18,6 @@ export class StorageController {
    * Puts the given message and data in storage.
    * @throws {DwnError} with `DwnErrorCode.StorageControllerDataCidMismatch`
    *                    if the data stream resulted in a data CID that mismatches with `dataCid` in the given message
-   * @throws {DwnError} with `DwnErrorCode.StorageControllerDataNotFound`
-   *                    if `dataCid` in `descriptor` is given, and `dataStream` is not given, and data for the message does not exist already
    * @throws {DwnError} with `DwnErrorCode.StorageControllerDataSizeMismatch`
    *                    if `dataSize` in `descriptor` given mismatches the actual data size
    */
@@ -35,26 +33,18 @@ export class StorageController {
     const messageCid = await Message.getCid(message);
 
     // if `dataCid` is given, it means there is corresponding data associated with this message
-    // but NOTE: it is possible that a data stream is not given in such case, for instance,
-    // a subsequent RecordsWrite that changes the `published` property, but the data hasn't changed,
-    // in this case requiring re-uploading of the data is extremely inefficient so we take care allow omission of data stream
     if (message.descriptor.dataCid !== undefined) {
       let result;
-
       if (dataStream === undefined) {
+        // but NOTE: it is possible that a data stream is not given even when `dataCid` is given, for instance,
+        // a subsequent RecordsWrite that changes the `published` property, but the data hasn't changed,
+        // in this case requiring re-uploading of the data is extremely inefficient so we allow omission of data stream as a utility function,
+        // but this method assumes checks for the appropriate conditions already took place prior to calling this method.
         result = await dataStore.associate(tenant, messageCid, message.descriptor.dataCid);
       } else {
         result = await dataStore.put(tenant, messageCid, message.descriptor.dataCid, dataStream);
       }
 
-      // the message implies that the data is already in the DB, so we check to make sure the data already exist
-      if (!result) {
-        throw new DwnError(
-          DwnErrorCode.StorageControllerDataNotFound,
-          `data with dataCid ${message.descriptor.dataCid} not found in store`
-        );
-      }
-
       // MUST verify that the size of the actual data matches with the given `dataSize`
       // if data size is wrong, delete the data we just stored
       if (message.descriptor.dataSize !== result.dataSize) {
diff --git a/src/utils/array.ts b/src/utils/array.ts
index e4c207897..2a2f0826b 100644
--- a/src/utils/array.ts
+++ b/src/utils/array.ts
@@ -1,11 +1,23 @@
-
 /**
- * Asynchronously iterates an {AsyncGenerator} to return all the values in an array.
+ * Array utility methods.
  */
-export async function asyncGeneratorToArray<T>(iterator: AsyncGenerator<T>): Promise<Array<T>> {
-  const array: Array<T> = [ ];
-  for await (const value of iterator) {
-    array.push(value);
+export class ArrayUtility {
+  /**
+   * Returns `true` if content of the two given byte arrays are equal; `false` otherwise.
+   */
+  public static byteArraysEqual(array1: Uint8Array, array2:Uint8Array): boolean {
+    const equal = array1.length === array2.length && array1.every((value, index) => value === array2[index]);
+    return equal;
+  }
+
+  /**
+   * Asynchronously iterates an {AsyncGenerator} to return all the values in an array.
+   */
+  public static async fromAsyncGenerator<T>(iterator: AsyncGenerator<T>): Promise<Array<T>> {
+    const array: Array<T> = [ ];
+    for await (const value of iterator) {
+      array.push(value);
+    }
+    return array;
   }
-  return array;
-}
+}
\ No newline at end of file
diff --git a/tests/interfaces/records/handlers/records-delete.spec.ts b/tests/interfaces/records/handlers/records-delete.spec.ts
index 9f158ee91..6eaa16297 100644
--- a/tests/interfaces/records/handlers/records-delete.spec.ts
+++ b/tests/interfaces/records/handlers/records-delete.spec.ts
@@ -2,11 +2,10 @@ import chaiAsPromised from 'chai-as-promised';
 import sinon from 'sinon';
 import chai, { expect } from 'chai';
 
-import { asyncGeneratorToArray } from '../../../../src/utils/array.js';
+import { ArrayUtility } from '../../../../src/utils/array.js';
 import { Cid } from '../../../../src/utils/cid.js';
 import { DataStoreLevel } from '../../../../src/store/data-store-level.js';
 import { DidKeyResolver } from '../../../../src/did/did-key-resolver.js';
-import { DwnErrorCode } from '../../../../src/core/dwn-error.js';
 import { EventLogLevel } from '../../../../src/event-log/event-log-level.js';
 import { Message } from '../../../../src/core/message.js';
 import { MessageStoreLevel } from '../../../../src/store/message-store-level.js';
@@ -131,249 +130,6 @@ describe('RecordsDeleteHandler.handle()', () => {
       expect(reply.entries![0].encodedData).to.equal(expectedEncodedData);
     });
 
-    it('should only write the data once even if written by multiple messages', async () => {
-      const alice = await DidKeyResolver.generate();
-      const data = Encoder.stringToBytes('test');
-      const dataCid = await Cid.computeDagPbCidFromBytes(data);
-      const encodedData = Encoder.bytesToBase64Url(data);
-
-      const blockstoreForData = await dataStore.blockstore.partition('data');
-      const blockstoreOfGivenTenant = await blockstoreForData.partition(alice.did);
-      const blockstoreOfGivenDataCid = await blockstoreOfGivenTenant.partition(dataCid);
-
-      const aliceWrite1Data = await TestDataGenerator.generateRecordsWrite({
-        requester: alice,
-        data
-      });
-      const aliceWrite1Reply = await dwn.processMessage(alice.did, aliceWrite1Data.message, aliceWrite1Data.dataStream);
-      expect(aliceWrite1Reply.status.code).to.equal(202);
-
-      const aliceQueryWrite1AfterAliceWrite1Data = await TestDataGenerator.generateRecordsQuery({
-        requester : alice,
-        filter    : { recordId: aliceWrite1Data.message.recordId }
-      });
-      const aliceQueryWrite1AfterAliceWrite1Reply = await dwn.processMessage(alice.did, aliceQueryWrite1AfterAliceWrite1Data.message);
-      expect(aliceQueryWrite1AfterAliceWrite1Reply.status.code).to.equal(200);
-      expect(aliceQueryWrite1AfterAliceWrite1Reply.entries?.length).to.equal(1);
-      expect(aliceQueryWrite1AfterAliceWrite1Reply.entries![0].encodedData).to.equal(encodedData);
-
-      await expect(asyncGeneratorToArray(blockstoreOfGivenDataCid.db.keys())).to.eventually.eql([ dataCid ]);
-
-      const aliceWrite2Data = await TestDataGenerator.generateRecordsWrite({
-        requester: alice,
-        data
-      });
-      const aliceWrite2Reply = await dwn.processMessage(alice.did, aliceWrite2Data.message, aliceWrite2Data.dataStream);
-      expect(aliceWrite2Reply.status.code).to.equal(202);
-
-      const aliceQueryWrite1AfterAliceWrite2Data = await TestDataGenerator.generateRecordsQuery({
-        requester : alice,
-        filter    : { recordId: aliceWrite1Data.message.recordId }
-      });
-      const aliceQueryWrite1AfterAliceWrite2Reply = await dwn.processMessage(alice.did, aliceQueryWrite1AfterAliceWrite2Data.message);
-      expect(aliceQueryWrite1AfterAliceWrite2Reply.status.code).to.equal(200);
-      expect(aliceQueryWrite1AfterAliceWrite2Reply.entries?.length).to.equal(1);
-      expect(aliceQueryWrite1AfterAliceWrite2Reply.entries![0].encodedData).to.equal(encodedData);
-
-      const aliceQueryWrite2AfterAliceWrite2Data = await TestDataGenerator.generateRecordsQuery({
-        requester : alice,
-        filter    : { recordId: aliceWrite2Data.message.recordId }
-      });
-      const aliceQueryWrite2AfterAliceWrite2Reply = await dwn.processMessage(alice.did, aliceQueryWrite2AfterAliceWrite2Data.message);
-      expect(aliceQueryWrite2AfterAliceWrite2Reply.status.code).to.equal(200);
-      expect(aliceQueryWrite2AfterAliceWrite2Reply.entries?.length).to.equal(1);
-      expect(aliceQueryWrite2AfterAliceWrite2Reply.entries![0].encodedData).to.equal(encodedData);
-
-      await expect(asyncGeneratorToArray(blockstoreOfGivenDataCid.db.keys())).to.eventually.eql([ dataCid ]);
-    });
-
-    it('should allow writing message by referencing existing data without supplying data again', async () => {
-      const alice = await DidKeyResolver.generate();
-      const data = Encoder.stringToBytes('test');
-      const dataCid = await Cid.computeDagPbCidFromBytes(data);
-      const encodedData = Encoder.bytesToBase64Url(data);
-
-      const blockstoreForData = await dataStore.blockstore.partition('data');
-      const blockstoreOfGivenTenant = await blockstoreForData.partition(alice.did);
-      const blockstoreOfGivenDataCid = await blockstoreOfGivenTenant.partition(dataCid);
-
-      const aliceWriteData = await TestDataGenerator.generateRecordsWrite({
-        requester: alice,
-        data
-      });
-      const aliceWriteReply = await dwn.processMessage(alice.did, aliceWriteData.message, aliceWriteData.dataStream);
-      expect(aliceWriteReply.status.code).to.equal(202);
-
-      const aliceQueryWriteAfterAliceWriteData = await TestDataGenerator.generateRecordsQuery({
-        requester : alice,
-        filter    : { recordId: aliceWriteData.message.recordId }
-      });
-      const aliceQueryWriteAfterAliceWriteReply = await dwn.processMessage(alice.did, aliceQueryWriteAfterAliceWriteData.message);
-      expect(aliceQueryWriteAfterAliceWriteReply.status.code).to.equal(200);
-      expect(aliceQueryWriteAfterAliceWriteReply.entries?.length).to.equal(1);
-      expect(aliceQueryWriteAfterAliceWriteReply.entries![0].encodedData).to.equal(encodedData);
-
-      await expect(asyncGeneratorToArray(blockstoreOfGivenDataCid.db.keys())).to.eventually.eql([ dataCid ]);
-
-      // referencing existing data without supplying the data again
-      const aliceAssociateData = await TestDataGenerator.generateRecordsWrite({
-        requester : alice,
-        dataCid,
-        dataSize  : 4
-      });
-      const aliceAssociateReply = await dwn.processMessage(alice.did, aliceAssociateData.message, aliceAssociateData.dataStream);
-      expect(aliceAssociateReply.status.code).to.equal(202);
-
-      const aliceQueryWriteAfterAliceAssociateData = await TestDataGenerator.generateRecordsQuery({
-        requester : alice,
-        filter    : { recordId: aliceWriteData.message.recordId }
-      });
-      const aliceQueryWriteAfterAliceAssociateReply = await dwn.processMessage(alice.did, aliceQueryWriteAfterAliceAssociateData.message);
-      expect(aliceQueryWriteAfterAliceAssociateReply.status.code).to.equal(200);
-      expect(aliceQueryWriteAfterAliceAssociateReply.entries?.length).to.equal(1);
-      expect(aliceQueryWriteAfterAliceAssociateReply.entries![0].encodedData).to.equal(encodedData);
-
-      const aliceQueryAssociateAfterAliceAssociateData = await TestDataGenerator.generateRecordsQuery({
-        requester : alice,
-        filter    : { recordId: aliceAssociateData.message.recordId }
-      });
-      const aliceQueryAssociateAfterAliceAssociateReply = await dwn.processMessage(alice.did, aliceQueryAssociateAfterAliceAssociateData.message);
-      expect(aliceQueryAssociateAfterAliceAssociateReply.status.code).to.equal(200);
-      expect(aliceQueryAssociateAfterAliceAssociateReply.entries?.length).to.equal(1);
-      expect(aliceQueryAssociateAfterAliceAssociateReply.entries![0].encodedData).to.equal(encodedData);
-
-      await expect(asyncGeneratorToArray(blockstoreOfGivenDataCid.db.keys())).to.eventually.eql([ dataCid ]);
-    });
-
-    it('should duplicate same data if written to different tenants', async () => {
-      const alice = await DidKeyResolver.generate();
-      const bob = await DidKeyResolver.generate();
-
-      const data = Encoder.stringToBytes('test');
-      const dataCid = await Cid.computeDagPbCidFromBytes(data);
-      const encodedData = Encoder.bytesToBase64Url(data);
-
-      const blockstoreForData = await dataStore.blockstore.partition('data');
-      const blockstoreOfAlice = await blockstoreForData.partition(alice.did);
-      const blockstoreOfAliceOfDataCid = await blockstoreOfAlice.partition(dataCid);
-
-      const blockstoreOfBob = await blockstoreForData.partition(bob.did);
-      const blockstoreOfBobOfDataCid = await blockstoreOfBob.partition(dataCid);
-
-      // write data to alice's DWN
-      const aliceWriteData = await TestDataGenerator.generateRecordsWrite({
-        requester: alice,
-        data
-      });
-      const aliceWriteReply = await dwn.processMessage(alice.did, aliceWriteData.message, aliceWriteData.dataStream);
-      expect(aliceWriteReply.status.code).to.equal(202);
-
-      const aliceQueryWriteAfterAliceWriteData = await TestDataGenerator.generateRecordsQuery({
-        requester : alice,
-        filter    : { recordId: aliceWriteData.message.recordId }
-      });
-      const aliceQueryWriteAfterAliceWriteReply = await dwn.processMessage(alice.did, aliceQueryWriteAfterAliceWriteData.message);
-      expect(aliceQueryWriteAfterAliceWriteReply.status.code).to.equal(200);
-      expect(aliceQueryWriteAfterAliceWriteReply.entries?.length).to.equal(1);
-      expect(aliceQueryWriteAfterAliceWriteReply.entries![0].encodedData).to.equal(encodedData);
-
-      // write same data to bob's DWN
-      const bobWriteData = await TestDataGenerator.generateRecordsWrite({
-        requester: bob,
-        data
-      });
-      const bobWriteReply = await dwn.processMessage(bob.did, bobWriteData.message, bobWriteData.dataStream);
-      expect(bobWriteReply.status.code).to.equal(202);
-
-      const aliceQueryWriteAfterBobWriteData = await TestDataGenerator.generateRecordsQuery({
-        requester : alice,
-        filter    : { recordId: aliceWriteData.message.recordId }
-      });
-      const aliceQueryWriteAfterBobWriteReply = await dwn.processMessage(alice.did, aliceQueryWriteAfterBobWriteData.message);
-      expect(aliceQueryWriteAfterBobWriteReply.status.code).to.equal(200);
-      expect(aliceQueryWriteAfterBobWriteReply.entries?.length).to.equal(1);
-      expect(aliceQueryWriteAfterBobWriteReply.entries![0].encodedData).to.equal(encodedData);
-
-      const bobQueryWriteAfterBobWriteData = await TestDataGenerator.generateRecordsQuery({
-        requester : bob,
-        filter    : { recordId: bobWriteData.message.recordId }
-      });
-      const bobQueryWriteAfterBobWriteReply = await dwn.processMessage(bob.did, bobQueryWriteAfterBobWriteData.message);
-      expect(bobQueryWriteAfterBobWriteReply.status.code).to.equal(200);
-      expect(bobQueryWriteAfterBobWriteReply.entries?.length).to.equal(1);
-      expect(bobQueryWriteAfterBobWriteReply.entries![0].encodedData).to.equal(encodedData);
-
-      // verify that both alice and bob's blockstore have reference to the same data CID
-      await expect(asyncGeneratorToArray(blockstoreOfAliceOfDataCid.db.keys())).to.eventually.eql([ dataCid ]);
-      await expect(asyncGeneratorToArray(blockstoreOfBobOfDataCid.db.keys())).to.eventually.eql([ dataCid ]);
-    });
-
-    it('should not allow referencing data across tenants', async () => {
-      const alice = await DidKeyResolver.generate();
-      const bob = await DidKeyResolver.generate();
-      const data = Encoder.stringToBytes('test');
-      const dataCid = await Cid.computeDagPbCidFromBytes(data);
-      const encodedData = Encoder.bytesToBase64Url(data);
-
-      const blockstoreForData = await dataStore.blockstore.partition('data');
-      const blockstoreOfAlice = await blockstoreForData.partition(alice.did);
-      const blockstoreOfAliceOfDataCid = await blockstoreOfAlice.partition(dataCid);
-
-      const blockstoreOfBob = await blockstoreForData.partition(bob.did);
-      const blockstoreOfBobOfDataCid = await blockstoreOfBob.partition(dataCid);
-
-      // alice writes data to her DWN
-      const aliceWriteData = await TestDataGenerator.generateRecordsWrite({
-        requester: alice,
-        data
-      });
-      const aliceWriteReply = await dwn.processMessage(alice.did, aliceWriteData.message, aliceWriteData.dataStream);
-      expect(aliceWriteReply.status.code).to.equal(202);
-
-      const aliceQueryWriteAfterAliceWriteData = await TestDataGenerator.generateRecordsQuery({
-        requester : alice,
-        filter    : { recordId: aliceWriteData.message.recordId }
-      });
-      const aliceQueryWriteAfterAliceWriteReply = await dwn.processMessage(alice.did, aliceQueryWriteAfterAliceWriteData.message);
-      expect(aliceQueryWriteAfterAliceWriteReply.status.code).to.equal(200);
-      expect(aliceQueryWriteAfterAliceWriteReply.entries?.length).to.equal(1);
-      expect(aliceQueryWriteAfterAliceWriteReply.entries![0].encodedData).to.equal(encodedData);
-
-      await expect(asyncGeneratorToArray(blockstoreOfAliceOfDataCid.db.keys())).to.eventually.eql([ dataCid ]);
-
-      // bob learns of the CID of data of alice and tries to gain unauthorized access by referencing it in his own DWN
-      const bobAssociateData = await TestDataGenerator.generateRecordsWrite({
-        requester : bob,
-        dataCid,
-        dataSize  : 4
-      });
-      const bobAssociateReply = await dwn.processMessage(bob.did, bobAssociateData.message, bobAssociateData.dataStream);
-      expect(bobAssociateReply.status.code).to.equal(400); // expecting an error
-      expect(bobAssociateReply.status.detail).to.contain(DwnErrorCode.StorageControllerDataNotFound);
-
-      const aliceQueryWriteAfterBobAssociateData = await TestDataGenerator.generateRecordsQuery({
-        requester : alice,
-        filter    : { recordId: aliceWriteData.message.recordId }
-      });
-      const aliceQueryWriteAfterBobAssociateReply = await dwn.processMessage(alice.did, aliceQueryWriteAfterBobAssociateData.message);
-      expect(aliceQueryWriteAfterBobAssociateReply.status.code).to.equal(200);
-      expect(aliceQueryWriteAfterBobAssociateReply.entries?.length).to.equal(1);
-      expect(aliceQueryWriteAfterBobAssociateReply.entries![0].encodedData).to.equal(encodedData);
-
-      // verify that bob has not gained access to alice's data
-      const bobQueryAssociateAfterBobAssociateData = await TestDataGenerator.generateRecordsQuery({
-        requester : bob,
-        filter    : { recordId: bobAssociateData.message.recordId }
-      });
-      const bobQueryAssociateAfterBobAssociateReply = await dwn.processMessage(bob.did, bobQueryAssociateAfterBobAssociateData.message);
-      expect(bobQueryAssociateAfterBobAssociateReply.status.code).to.equal(200);
-      expect(bobQueryAssociateAfterBobAssociateReply.entries?.length).to.equal(0);
-
-      // verify that bob's blockstore does not contain alice's data
-      await expect(asyncGeneratorToArray(blockstoreOfAliceOfDataCid.db.keys())).to.eventually.eql([ dataCid ]);
-      await expect(asyncGeneratorToArray(blockstoreOfBobOfDataCid.db.keys())).to.eventually.eql([ ]);
-    });
-
     it('should be able to delete and rewrite the same data', async () => {
       const alice = await DidKeyResolver.generate();
       const data = Encoder.stringToBytes('test');
@@ -401,7 +157,7 @@ describe('RecordsDeleteHandler.handle()', () => {
       expect(aliceQueryWriteAfterAliceWriteReply.entries?.length).to.equal(1);
       expect(aliceQueryWriteAfterAliceWriteReply.entries![0].encodedData).to.equal(encodedData);
 
-      await expect(asyncGeneratorToArray(blockstoreOfAliceOfDataCid.db.keys())).to.eventually.eql([ dataCid ]);
+      await expect(ArrayUtility.fromAsyncGenerator(blockstoreOfAliceOfDataCid.db.keys())).to.eventually.eql([ dataCid ]);
 
       // alice deleting the record
       const aliceDeleteWriteData = await TestDataGenerator.generateRecordsDelete({
@@ -419,7 +175,7 @@ describe('RecordsDeleteHandler.handle()', () => {
       expect(aliceQueryWriteAfterAliceDeleteReply.status.code).to.equal(200);
       expect(aliceQueryWriteAfterAliceDeleteReply.entries?.length).to.equal(0);
 
-      await expect(asyncGeneratorToArray(blockstoreOfAliceOfDataCid.db.keys())).to.eventually.eql([ ]);
+      await expect(ArrayUtility.fromAsyncGenerator(blockstoreOfAliceOfDataCid.db.keys())).to.eventually.eql([ ]);
 
       // alice writes a new record with the same data
       const aliceRewriteData = await TestDataGenerator.generateRecordsWrite({
@@ -438,7 +194,7 @@ describe('RecordsDeleteHandler.handle()', () => {
       expect(aliceQueryWriteAfterAliceRewriteReply.entries?.length).to.equal(1);
       expect(aliceQueryWriteAfterAliceRewriteReply.entries![0].encodedData).to.equal(encodedData);
 
-      await expect(asyncGeneratorToArray(blockstoreOfAliceOfDataCid.db.keys())).to.eventually.eql([ dataCid ]);
+      await expect(ArrayUtility.fromAsyncGenerator(blockstoreOfAliceOfDataCid.db.keys())).to.eventually.eql([ dataCid ]);
     });
 
     it('should only delete data after all messages referencing it are deleted', async () => {
@@ -455,46 +211,32 @@ describe('RecordsDeleteHandler.handle()', () => {
       const blockstoreOfBobOfDataCid = await blockstoreOfBob.partition(dataCid);
 
       // alice writes a records with data
-      const aliceWriteData = await TestDataGenerator.generateRecordsWrite({
-        requester: alice,
-        data
-      });
+      const aliceWriteData = await TestDataGenerator.generateRecordsWrite({ requester: alice, data });
       const aliceWriteReply = await dwn.processMessage(alice.did, aliceWriteData.message, aliceWriteData.dataStream);
       expect(aliceWriteReply.status.code).to.equal(202);
 
-      await expect(asyncGeneratorToArray(blockstoreOfAliceOfDataCid.db.keys())).to.eventually.eql([ dataCid ]);
+      await expect(ArrayUtility.fromAsyncGenerator(blockstoreOfAliceOfDataCid.db.keys())).to.eventually.eql([ dataCid ]);
 
-      // alice writes another record referencing the same data
-      const aliceAssociateData = await TestDataGenerator.generateRecordsWrite({
-        requester : alice,
-        dataCid,
-        dataSize  : 4
-      });
+      // alice writes another record with the same data
+      const aliceAssociateData = await TestDataGenerator.generateRecordsWrite({ requester: alice, data });
       const aliceAssociateReply = await dwn.processMessage(alice.did, aliceAssociateData.message, aliceAssociateData.dataStream);
       expect(aliceAssociateReply.status.code).to.equal(202);
 
-      await expect(asyncGeneratorToArray(blockstoreOfAliceOfDataCid.db.keys())).to.eventually.eql([ dataCid ]);
+      await expect(ArrayUtility.fromAsyncGenerator(blockstoreOfAliceOfDataCid.db.keys())).to.eventually.eql([ dataCid ]);
 
       // bob writes a records with same data
-      const bobWriteData = await TestDataGenerator.generateRecordsWrite({
-        requester: bob,
-        data
-      });
+      const bobWriteData = await TestDataGenerator.generateRecordsWrite({ requester: bob, data });
       const bobWriteReply = await dwn.processMessage(bob.did, bobWriteData.message, bobWriteData.dataStream);
       expect(bobWriteReply.status.code).to.equal(202);
 
-      await expect(asyncGeneratorToArray(blockstoreOfBobOfDataCid.db.keys())).to.eventually.eql([ dataCid ]);
+      await expect(ArrayUtility.fromAsyncGenerator(blockstoreOfBobOfDataCid.db.keys())).to.eventually.eql([ dataCid ]);
 
-      // bob writes another record referencing the same data
-      const bobAssociateData = await TestDataGenerator.generateRecordsWrite({
-        requester : bob,
-        dataCid,
-        dataSize  : 4
-      });
+      // bob writes another record with the same data
+      const bobAssociateData = await TestDataGenerator.generateRecordsWrite({ requester: bob, data });
       const bobAssociateReply = await dwn.processMessage(bob.did, bobAssociateData.message, bobAssociateData.dataStream);
       expect(bobAssociateReply.status.code).to.equal(202);
 
-      await expect(asyncGeneratorToArray(blockstoreOfBobOfDataCid.db.keys())).to.eventually.eql([ dataCid ]);
+      await expect(ArrayUtility.fromAsyncGenerator(blockstoreOfBobOfDataCid.db.keys())).to.eventually.eql([ dataCid ]);
 
       // alice deletes one of the two records
       const aliceDeleteWriteData = await TestDataGenerator.generateRecordsDelete({
@@ -504,7 +246,7 @@ describe('RecordsDeleteHandler.handle()', () => {
       const aliceDeleteWriteReply = await dwn.processMessage(alice.did, aliceDeleteWriteData.message);
       expect(aliceDeleteWriteReply.status.code).to.equal(202);
 
-      await expect(asyncGeneratorToArray(blockstoreOfAliceOfDataCid.db.keys())).to.eventually.eql([ dataCid ]);
+      await expect(ArrayUtility.fromAsyncGenerator(blockstoreOfAliceOfDataCid.db.keys())).to.eventually.eql([ dataCid ]);
 
       // alice deletes the other record
       const aliceDeleteAssociateData = await TestDataGenerator.generateRecordsDelete({
@@ -515,8 +257,8 @@ describe('RecordsDeleteHandler.handle()', () => {
       expect(aliceDeleteAssociateReply.status.code).to.equal(202);
 
       // verify that data is deleted in alice's blockstore, but remains in bob's blockstore
-      await expect(asyncGeneratorToArray(blockstoreOfAliceOfDataCid.db.keys())).to.eventually.eql([ ]);
-      await expect(asyncGeneratorToArray(blockstoreOfBobOfDataCid.db.keys())).to.eventually.eql([ dataCid ]);
+      await expect(ArrayUtility.fromAsyncGenerator(blockstoreOfAliceOfDataCid.db.keys())).to.eventually.eql([ ]);
+      await expect(ArrayUtility.fromAsyncGenerator(blockstoreOfBobOfDataCid.db.keys())).to.eventually.eql([ dataCid ]);
     });
 
     describe('event log', () => {
diff --git a/tests/interfaces/records/handlers/records-query.spec.ts b/tests/interfaces/records/handlers/records-query.spec.ts
index 438915c92..3e0a6c8c7 100644
--- a/tests/interfaces/records/handlers/records-query.spec.ts
+++ b/tests/interfaces/records/handlers/records-query.spec.ts
@@ -6,7 +6,7 @@ import emailProtocolDefinition from '../../../vectors/protocol-definitions/email
 import sinon from 'sinon';
 import chai, { expect } from 'chai';
 
-import { Comparer } from '../../../utils/comparer.js';
+import { ArrayUtility } from '../../../../src/utils/array.js';
 import { DataStoreLevel } from '../../../../src/store/data-store-level.js';
 import { DidKeyResolver } from '../../../../src/did/did-key-resolver.js';
 import { DwnConstant } from '../../../../src/core/dwn-constant.js';
@@ -718,7 +718,7 @@ describe('RecordsQueryHandler.handle()', () => {
 
         const plaintextDataStream = await Records.decrypt(unsignedRecordsWrite, rootPrivateKey, cipherStream);
         const plaintextBytes = await DataStream.toBytes(plaintextDataStream);
-        expect(Comparer.byteArraysEqual(plaintextBytes, bobMessageBytes)).to.be.true;
+        expect(ArrayUtility.byteArraysEqual(plaintextBytes, bobMessageBytes)).to.be.true;
 
 
         // test able to decrypt the message using a derived key
@@ -729,7 +729,7 @@ describe('RecordsQueryHandler.handle()', () => {
 
         const plaintextDataStream2 = await Records.decrypt(unsignedRecordsWrite, derivedPrivateKey, cipherStream2);
         const plaintextBytes2 = await DataStream.toBytes(plaintextDataStream2);
-        expect(Comparer.byteArraysEqual(plaintextBytes2, bobMessageBytes)).to.be.true;
+        expect(ArrayUtility.byteArraysEqual(plaintextBytes2, bobMessageBytes)).to.be.true;
 
 
         // test able to decrypt the message using a key derived from a derived key
@@ -740,7 +740,7 @@ describe('RecordsQueryHandler.handle()', () => {
 
         const plaintextDataStream3 = await Records.decrypt(unsignedRecordsWrite, derivedPrivateKey2, cipherStream3);
         const plaintextBytes3 = await DataStream.toBytes(plaintextDataStream3);
-        expect(Comparer.byteArraysEqual(plaintextBytes3, bobMessageBytes)).to.be.true;
+        expect(ArrayUtility.byteArraysEqual(plaintextBytes3, bobMessageBytes)).to.be.true;
 
 
         // test unable to decrypt the message if derived key has an unexpected path
@@ -802,7 +802,7 @@ describe('RecordsQueryHandler.handle()', () => {
 
         const plaintextDataStream = await Records.decrypt(unsignedRecordsWrite, rootPrivateKey, cipherStream);
         const plaintextBytes = await DataStream.toBytes(plaintextDataStream);
-        expect(Comparer.byteArraysEqual(plaintextBytes, originalData)).to.be.true;
+        expect(ArrayUtility.byteArraysEqual(plaintextBytes, originalData)).to.be.true;
 
 
         // test able to decrypt the message using a derived key
@@ -813,7 +813,7 @@ describe('RecordsQueryHandler.handle()', () => {
 
         const plaintextDataStream2 = await Records.decrypt(unsignedRecordsWrite, derivedPrivateKey, cipherStream2);
         const plaintextBytes2 = await DataStream.toBytes(plaintextDataStream2);
-        expect(Comparer.byteArraysEqual(plaintextBytes2, originalData)).to.be.true;
+        expect(ArrayUtility.byteArraysEqual(plaintextBytes2, originalData)).to.be.true;
 
 
         // test able to decrypt the message using a key derived from a derived key
@@ -824,7 +824,7 @@ describe('RecordsQueryHandler.handle()', () => {
 
         const plaintextDataStream3 = await Records.decrypt(unsignedRecordsWrite, derivedPrivateKey2, cipherStream3);
         const plaintextBytes3 = await DataStream.toBytes(plaintextDataStream3);
-        expect(Comparer.byteArraysEqual(plaintextBytes3, originalData)).to.be.true;
+        expect(ArrayUtility.byteArraysEqual(plaintextBytes3, originalData)).to.be.true;
 
 
         // test unable to decrypt the message if derived key has an unexpected path
diff --git a/tests/interfaces/records/handlers/records-read.spec.ts b/tests/interfaces/records/handlers/records-read.spec.ts
index 1fd8f589a..3ff25289d 100644
--- a/tests/interfaces/records/handlers/records-read.spec.ts
+++ b/tests/interfaces/records/handlers/records-read.spec.ts
@@ -7,7 +7,7 @@ import sinon from 'sinon';
 import socialMediaProtocolDefinition from '../../../vectors/protocol-definitions/social-media.json' assert { type: 'json' };
 import chai, { expect } from 'chai';
 
-import { Comparer } from '../../../utils/comparer.js';
+import { ArrayUtility } from '../../../../src/utils/array.js';
 import { DataStoreLevel } from '../../../../src/store/data-store-level.js';
 import { DidKeyResolver } from '../../../../src/did/did-key-resolver.js';
 import { DwnErrorCode } from '../../../../src/core/dwn-error.js';
@@ -86,7 +86,7 @@ describe('RecordsReadHandler.handle()', () => {
       expect(readReply.record?.descriptor).to.exist;
 
       const dataFetched = await DataStream.toBytes(readReply.record!.data!);
-      expect(Comparer.byteArraysEqual(dataFetched, dataBytes!)).to.be.true;
+      expect(ArrayUtility.byteArraysEqual(dataFetched, dataBytes!)).to.be.true;
     });
 
     it('should not allow non-tenant to RecordsRead their a record data', async () => {
@@ -127,7 +127,7 @@ describe('RecordsReadHandler.handle()', () => {
       expect(readReply.status.code).to.equal(200);
 
       const dataFetched = await DataStream.toBytes(readReply.record!.data!);
-      expect(Comparer.byteArraysEqual(dataFetched, dataBytes!)).to.be.true;
+      expect(ArrayUtility.byteArraysEqual(dataFetched, dataBytes!)).to.be.true;
     });
 
     it('should allow an authenticated user to RecordRead data that is published', async () => {
@@ -150,7 +150,7 @@ describe('RecordsReadHandler.handle()', () => {
       expect(readReply.status.code).to.equal(200);
 
       const dataFetched = await DataStream.toBytes(readReply.record!.data!);
-      expect(Comparer.byteArraysEqual(dataFetched, dataBytes!)).to.be.true;
+      expect(ArrayUtility.byteArraysEqual(dataFetched, dataBytes!)).to.be.true;
     });
 
     describe('protocol based reads', () => {
@@ -420,7 +420,7 @@ describe('RecordsReadHandler.handle()', () => {
 
         const plaintextDataStream = await Records.decrypt(unsignedRecordsWrite, rootPrivateKey, cipherStream);
         const plaintextBytes = await DataStream.toBytes(plaintextDataStream);
-        expect(Comparer.byteArraysEqual(plaintextBytes, originalData)).to.be.true;
+        expect(ArrayUtility.byteArraysEqual(plaintextBytes, originalData)).to.be.true;
 
 
         // test able to decrypt the message using a derived key
@@ -433,7 +433,7 @@ describe('RecordsReadHandler.handle()', () => {
 
         const plaintextDataStream2 = await Records.decrypt(unsignedRecordsWrite, derivedPrivateKey, cipherStream2);
         const plaintextBytes2 = await DataStream.toBytes(plaintextDataStream2);
-        expect(Comparer.byteArraysEqual(plaintextBytes2, originalData)).to.be.true;
+        expect(ArrayUtility.byteArraysEqual(plaintextBytes2, originalData)).to.be.true;
 
 
         // test unable to decrypt the message if derived key has an unexpected path
@@ -526,7 +526,7 @@ describe('RecordsReadHandler.handle()', () => {
 
         const plaintextDataStream = await Records.decrypt(unsignedRecordsWrite, descendantPrivateKey, cipherStream);
         const plaintextBytes = await DataStream.toBytes(plaintextDataStream);
-        expect(Comparer.byteArraysEqual(plaintextBytes, bobMessageBytes)).to.be.true;
+        expect(ArrayUtility.byteArraysEqual(plaintextBytes, bobMessageBytes)).to.be.true;
 
         // test unable to decrypt the message if derived key has an unexpected path
         const invalidDerivationPath = [KeyDerivationScheme.Protocols, protocol, 'invalidContextId'];
diff --git a/tests/interfaces/records/handlers/records-write.spec.ts b/tests/interfaces/records/handlers/records-write.spec.ts
index df0703039..3d9d4ff18 100644
--- a/tests/interfaces/records/handlers/records-write.spec.ts
+++ b/tests/interfaces/records/handlers/records-write.spec.ts
@@ -13,7 +13,7 @@ import sinon from 'sinon';
 import socialMediaProtocolDefinition from '../../../vectors/protocol-definitions/social-media.json' assert { type: 'json' };
 import chai, { expect } from 'chai';
 
-import { asyncGeneratorToArray } from '../../../../src/utils/array.js';
+import { ArrayUtility } from '../../../../src/utils/array.js';
 import { base64url } from 'multiformats/bases/base64';
 import { DataStoreLevel } from '../../../../src/store/data-store-level.js';
 import { DataStream } from '../../../../src/utils/data-stream.js';
@@ -30,6 +30,7 @@ import { KeyDerivationScheme } from '../../../../src/index.js';
 import { Message } from '../../../../src/core/message.js';
 import { MessageStoreLevel } from '../../../../src/store/message-store-level.js';
 import { ProtocolActor } from '../../../../src/interfaces/protocols/types.js';
+import { RecordsRead } from '../../../../src/interfaces/records/messages/records-read.js';
 import { RecordsWrite } from '../../../../src/interfaces/records/messages/records-write.js';
 import { RecordsWriteHandler } from '../../../../src/interfaces/records/handlers/records-write.js';
 import { StorageController } from '../../../../src/store/storage-controller.js';
@@ -308,7 +309,7 @@ describe('RecordsWriteHandler.handle()', () => {
       expect(reply.status.detail).to.contain('does not match dataCid in descriptor');
     });
 
-    it('should return 400 if attempting to write a record without data stream and the data does not already exist in DWN', async () => {
+    it('should return 400 if attempting to write a record without data stream', async () => {
       const alice = await DidKeyResolver.generate();
 
       const { message } = await TestDataGenerator.generateRecordsWrite({
@@ -318,7 +319,62 @@ describe('RecordsWriteHandler.handle()', () => {
       const reply = await dwn.processMessage(alice.did, message);
 
       expect(reply.status.code).to.equal(400);
-      expect(reply.status.detail).to.contain(DwnErrorCode.StorageControllerDataNotFound);
+      expect(reply.status.detail).to.contain(DwnErrorCode.RecordsWriteMissingDataStream);
+    });
+
+    it('#359 - should not allow access of data by referencing a different`dataCid` in "modify" `RecordsWrite`', async () => {
+      const alice = await DidKeyResolver.generate();
+
+      // alice writes a record
+      const dataString = 'private data';
+      const dataSize = dataString.length;
+      const data = Encoder.stringToBytes(dataString);
+      const dataCid = await Cid.computeDagPbCidFromBytes(data);
+
+      const write1 = await TestDataGenerator.generateRecordsWrite({
+        requester: alice,
+        data,
+      });
+
+      const write1Reply = await dwn.processMessage(alice.did, write1.message, write1.dataStream);
+      expect(write1Reply.status.code).to.equal(202);
+
+      // alice writes another record (which will be modified later)
+      const write2 = await TestDataGenerator.generateRecordsWrite({ requester: alice });
+      const write2Reply = await dwn.processMessage(alice.did, write2.message, write2.dataStream);
+      expect(write2Reply.status.code).to.equal(202);
+
+      // modify write2 by referencing the `dataCid` in write1 (which should not be allowed)
+      const write2Change = await TestDataGenerator.generateRecordsWrite({
+        requester    : alice,
+        // immutable properties just inherit from the message given
+        recipientDid : write2.message.descriptor.recipient,
+        recordId     : write2.message.recordId,
+        dateCreated  : write2.message.descriptor.dateCreated,
+        contextId    : write2.message.contextId,
+        protocolPath : write2.message.descriptor.protocolPath,
+        parentId     : write2.message.descriptor.parentId,
+        schema       : write2.message.descriptor.schema,
+        dataFormat   : write2.message.descriptor.dataFormat,
+        // unauthorized reference to data in write1
+        dataCid,
+        dataSize
+      });
+      const write2ChangeReply = await dwn.processMessage(alice.did, write2Change.message);
+      expect(write2ChangeReply.status.code).to.equal(400); // should be disallowed
+      expect(write2ChangeReply.status.detail).to.contain(DwnErrorCode.RecordsWriteMissingDataStream);
+
+      // further sanity test to make sure the change is not written, ie. write2 still has the original data
+      const read = await RecordsRead.create({
+        recordId                    : write2.message.recordId,
+        authorizationSignatureInput : Jws.createSignatureInput(alice)
+      });
+
+      const readReply = await dwn.handleRecordsRead(alice.did, read.message);
+      expect(readReply.status.code).to.equal(200);
+
+      const readDataBytes = await DataStream.toBytes(readReply.record!.data!);
+      expect(ArrayUtility.byteArraysEqual(readDataBytes, write2.dataBytes!)).to.be.true;
     });
 
     describe('initial write & subsequent write tests', () => {
@@ -342,7 +398,7 @@ describe('RecordsWriteHandler.handle()', () => {
           const reply = await dwn.processMessage(tenant, message, dataStream);
           expect(reply.status.code).to.equal(202);
 
-          expect(asyncGeneratorToArray(dataForCid.db.keys())).to.eventually.eql([ dataCid ]);
+          expect(ArrayUtility.fromAsyncGenerator(dataForCid.db.keys())).to.eventually.eql([ dataCid ]);
 
           const newWrite = await RecordsWrite.createFrom({
             unsignedRecordsWriteMessage : recordsWrite.message,
@@ -353,7 +409,7 @@ describe('RecordsWriteHandler.handle()', () => {
           const newWriteReply = await dwn.processMessage(tenant, newWrite.message);
           expect(newWriteReply.status.code).to.equal(202);
 
-          expect(asyncGeneratorToArray(dataForCid.db.keys())).to.eventually.eql([ dataCid ]);
+          expect(ArrayUtility.fromAsyncGenerator(dataForCid.db.keys())).to.eventually.eql([ dataCid ]);
 
           // verify the new record state can be queried
           const recordsQueryMessageData = await TestDataGenerator.generateRecordsQuery({
@@ -369,7 +425,7 @@ describe('RecordsWriteHandler.handle()', () => {
           // very importantly verify the original data is still returned
           expect(recordsQueryReply.entries![0].encodedData).to.equal(encodedData);
 
-          expect(asyncGeneratorToArray(dataForCid.db.keys())).to.eventually.eql([ dataCid ]);
+          expect(ArrayUtility.fromAsyncGenerator(dataForCid.db.keys())).to.eventually.eql([ dataCid ]);
         });
 
         it('should inherit parent published state when using createFrom() to create RecordsWrite', async () => {
@@ -1543,6 +1599,253 @@ describe('RecordsWriteHandler.handle()', () => {
         expect(reply.status.code).to.equal(400);
         expect(reply.status.detail).to.contain(DwnErrorCode.UrlProtocolNotNormalized);
       });
+
+      it('#359 - should not allow access of data by referencing `dataCid` in protocol authorized `RecordsWrite`', async () => {
+        const alice = await DidKeyResolver.generate();
+        const bob = await DidKeyResolver.generate();
+
+        const dataForCid = await dataStore.blockstore.partition('data');
+
+        // alice writes a private record
+        const dataString = 'private data';
+        const dataSize = dataString.length;
+        const data = Encoder.stringToBytes(dataString);
+        const dataCid = await Cid.computeDagPbCidFromBytes(data);
+
+        const { message, dataStream } = await TestDataGenerator.generateRecordsWrite({
+          requester: alice,
+          data,
+        });
+
+        const reply = await dwn.processMessage(alice.did, message, dataStream);
+        expect(reply.status.code).to.equal(202);
+
+        expect(ArrayUtility.fromAsyncGenerator(dataForCid.db.keys())).to.eventually.eql([ dataCid ]);
+
+        const protocol = 'https://tbd.website/decentralized-web-node/protocols/social-media';
+        const protocolDefinition = socialMediaProtocolDefinition;
+
+        // alice has a social media protocol that allows anyone to write and read images
+        const protocolsConfig = await TestDataGenerator.generateProtocolsConfigure({
+          requester: alice,
+          protocol,
+          protocolDefinition
+        });
+        const protocolWriteReply = await dwn.processMessage(alice.did, protocolsConfig.message, protocolsConfig.dataStream);
+        expect(protocolWriteReply.status.code).to.equal(202);
+
+        // bob learns of metadata (ie. dataCid) of alice's secret data,
+        // attempts to gain unauthorized access by writing to alice's DWN through open protocol referencing the dataCid without supplying the data
+        const imageRecordsWrite = await TestDataGenerator.generateRecordsWrite({
+          requester    : bob,
+          protocol,
+          protocolPath : 'image',
+          schema       : protocolDefinition.types.image.schema,
+          dataFormat   : 'image/jpeg',
+          dataCid, // bob learns of, and references alice's secrete data's CID
+          dataSize,
+          recipientDid : alice.did
+        });
+        const imageReply = await dwn.processMessage(alice.did, imageRecordsWrite.message, imageRecordsWrite.dataStream);
+        expect(imageReply.status.code).to.equal(400); // should be disallowed
+        expect(imageReply.status.detail).to.contain(DwnErrorCode.RecordsWriteMissingDataStream);
+
+        // further sanity test to make sure record is never written
+        const bobRecordsReadData = await RecordsRead.create({
+          recordId                    : imageRecordsWrite.message.recordId,
+          authorizationSignatureInput : Jws.createSignatureInput(bob)
+        });
+
+        const bobRecordsReadReply = await dwn.handleRecordsRead(alice.did, bobRecordsReadData.message);
+        expect(bobRecordsReadReply.status.code).to.equal(404);
+      });
+    });
+
+    describe('reference counting tests', () => {
+      it('should only write the data once even if written by multiple messages', async () => {
+        const alice = await DidKeyResolver.generate();
+        const data = Encoder.stringToBytes('test');
+        const dataCid = await Cid.computeDagPbCidFromBytes(data);
+        const encodedData = Encoder.bytesToBase64Url(data);
+
+        const blockstoreForData = await dataStore.blockstore.partition('data');
+        const blockstoreOfGivenTenant = await blockstoreForData.partition(alice.did);
+        const blockstoreOfGivenDataCid = await blockstoreOfGivenTenant.partition(dataCid);
+
+        const aliceWrite1Data = await TestDataGenerator.generateRecordsWrite({
+          requester: alice,
+          data
+        });
+        const aliceWrite1Reply = await dwn.processMessage(alice.did, aliceWrite1Data.message, aliceWrite1Data.dataStream);
+        expect(aliceWrite1Reply.status.code).to.equal(202);
+
+        const aliceQueryWrite1AfterAliceWrite1Data = await TestDataGenerator.generateRecordsQuery({
+          requester : alice,
+          filter    : { recordId: aliceWrite1Data.message.recordId }
+        });
+        const aliceQueryWrite1AfterAliceWrite1Reply = await dwn.processMessage(alice.did, aliceQueryWrite1AfterAliceWrite1Data.message);
+        expect(aliceQueryWrite1AfterAliceWrite1Reply.status.code).to.equal(200);
+        expect(aliceQueryWrite1AfterAliceWrite1Reply.entries?.length).to.equal(1);
+        expect(aliceQueryWrite1AfterAliceWrite1Reply.entries![0].encodedData).to.equal(encodedData);
+
+        await expect(ArrayUtility.fromAsyncGenerator(blockstoreOfGivenDataCid.db.keys())).to.eventually.eql([ dataCid ]);
+
+        const aliceWrite2Data = await TestDataGenerator.generateRecordsWrite({
+          requester: alice,
+          data
+        });
+        const aliceWrite2Reply = await dwn.processMessage(alice.did, aliceWrite2Data.message, aliceWrite2Data.dataStream);
+        expect(aliceWrite2Reply.status.code).to.equal(202);
+
+        const aliceQueryWrite1AfterAliceWrite2Data = await TestDataGenerator.generateRecordsQuery({
+          requester : alice,
+          filter    : { recordId: aliceWrite1Data.message.recordId }
+        });
+        const aliceQueryWrite1AfterAliceWrite2Reply = await dwn.processMessage(alice.did, aliceQueryWrite1AfterAliceWrite2Data.message);
+        expect(aliceQueryWrite1AfterAliceWrite2Reply.status.code).to.equal(200);
+        expect(aliceQueryWrite1AfterAliceWrite2Reply.entries?.length).to.equal(1);
+        expect(aliceQueryWrite1AfterAliceWrite2Reply.entries![0].encodedData).to.equal(encodedData);
+
+        const aliceQueryWrite2AfterAliceWrite2Data = await TestDataGenerator.generateRecordsQuery({
+          requester : alice,
+          filter    : { recordId: aliceWrite2Data.message.recordId }
+        });
+        const aliceQueryWrite2AfterAliceWrite2Reply = await dwn.processMessage(alice.did, aliceQueryWrite2AfterAliceWrite2Data.message);
+        expect(aliceQueryWrite2AfterAliceWrite2Reply.status.code).to.equal(200);
+        expect(aliceQueryWrite2AfterAliceWrite2Reply.entries?.length).to.equal(1);
+        expect(aliceQueryWrite2AfterAliceWrite2Reply.entries![0].encodedData).to.equal(encodedData);
+
+        await expect(ArrayUtility.fromAsyncGenerator(blockstoreOfGivenDataCid.db.keys())).to.eventually.eql([ dataCid ]);
+      });
+
+      it('should duplicate same data if written to different tenants', async () => {
+        const alice = await DidKeyResolver.generate();
+        const bob = await DidKeyResolver.generate();
+
+        const data = Encoder.stringToBytes('test');
+        const dataCid = await Cid.computeDagPbCidFromBytes(data);
+        const encodedData = Encoder.bytesToBase64Url(data);
+
+        const blockstoreForData = await dataStore.blockstore.partition('data');
+        const blockstoreOfAlice = await blockstoreForData.partition(alice.did);
+        const blockstoreOfAliceOfDataCid = await blockstoreOfAlice.partition(dataCid);
+
+        const blockstoreOfBob = await blockstoreForData.partition(bob.did);
+        const blockstoreOfBobOfDataCid = await blockstoreOfBob.partition(dataCid);
+
+        // write data to alice's DWN
+        const aliceWriteData = await TestDataGenerator.generateRecordsWrite({
+          requester: alice,
+          data
+        });
+        const aliceWriteReply = await dwn.processMessage(alice.did, aliceWriteData.message, aliceWriteData.dataStream);
+        expect(aliceWriteReply.status.code).to.equal(202);
+
+        const aliceQueryWriteAfterAliceWriteData = await TestDataGenerator.generateRecordsQuery({
+          requester : alice,
+          filter    : { recordId: aliceWriteData.message.recordId }
+        });
+        const aliceQueryWriteAfterAliceWriteReply = await dwn.processMessage(alice.did, aliceQueryWriteAfterAliceWriteData.message);
+        expect(aliceQueryWriteAfterAliceWriteReply.status.code).to.equal(200);
+        expect(aliceQueryWriteAfterAliceWriteReply.entries?.length).to.equal(1);
+        expect(aliceQueryWriteAfterAliceWriteReply.entries![0].encodedData).to.equal(encodedData);
+
+        // write same data to bob's DWN
+        const bobWriteData = await TestDataGenerator.generateRecordsWrite({
+          requester: bob,
+          data
+        });
+        const bobWriteReply = await dwn.processMessage(bob.did, bobWriteData.message, bobWriteData.dataStream);
+        expect(bobWriteReply.status.code).to.equal(202);
+
+        const aliceQueryWriteAfterBobWriteData = await TestDataGenerator.generateRecordsQuery({
+          requester : alice,
+          filter    : { recordId: aliceWriteData.message.recordId }
+        });
+        const aliceQueryWriteAfterBobWriteReply = await dwn.processMessage(alice.did, aliceQueryWriteAfterBobWriteData.message);
+        expect(aliceQueryWriteAfterBobWriteReply.status.code).to.equal(200);
+        expect(aliceQueryWriteAfterBobWriteReply.entries?.length).to.equal(1);
+        expect(aliceQueryWriteAfterBobWriteReply.entries![0].encodedData).to.equal(encodedData);
+
+        const bobQueryWriteAfterBobWriteData = await TestDataGenerator.generateRecordsQuery({
+          requester : bob,
+          filter    : { recordId: bobWriteData.message.recordId }
+        });
+        const bobQueryWriteAfterBobWriteReply = await dwn.processMessage(bob.did, bobQueryWriteAfterBobWriteData.message);
+        expect(bobQueryWriteAfterBobWriteReply.status.code).to.equal(200);
+        expect(bobQueryWriteAfterBobWriteReply.entries?.length).to.equal(1);
+        expect(bobQueryWriteAfterBobWriteReply.entries![0].encodedData).to.equal(encodedData);
+
+        // verify that both alice and bob's blockstore have reference to the same data CID
+        await expect(ArrayUtility.fromAsyncGenerator(blockstoreOfAliceOfDataCid.db.keys())).to.eventually.eql([ dataCid ]);
+        await expect(ArrayUtility.fromAsyncGenerator(blockstoreOfBobOfDataCid.db.keys())).to.eventually.eql([ dataCid ]);
+      });
+
+      it('should not allow referencing data across tenants', async () => {
+        const alice = await DidKeyResolver.generate();
+        const bob = await DidKeyResolver.generate();
+        const data = Encoder.stringToBytes('test');
+        const dataCid = await Cid.computeDagPbCidFromBytes(data);
+        const encodedData = Encoder.bytesToBase64Url(data);
+
+        const blockstoreForData = await dataStore.blockstore.partition('data');
+        const blockstoreOfAlice = await blockstoreForData.partition(alice.did);
+        const blockstoreOfAliceOfDataCid = await blockstoreOfAlice.partition(dataCid);
+
+        const blockstoreOfBob = await blockstoreForData.partition(bob.did);
+        const blockstoreOfBobOfDataCid = await blockstoreOfBob.partition(dataCid);
+
+        // alice writes data to her DWN
+        const aliceWriteData = await TestDataGenerator.generateRecordsWrite({
+          requester: alice,
+          data
+        });
+        const aliceWriteReply = await dwn.processMessage(alice.did, aliceWriteData.message, aliceWriteData.dataStream);
+        expect(aliceWriteReply.status.code).to.equal(202);
+
+        const aliceQueryWriteAfterAliceWriteData = await TestDataGenerator.generateRecordsQuery({
+          requester : alice,
+          filter    : { recordId: aliceWriteData.message.recordId }
+        });
+        const aliceQueryWriteAfterAliceWriteReply = await dwn.processMessage(alice.did, aliceQueryWriteAfterAliceWriteData.message);
+        expect(aliceQueryWriteAfterAliceWriteReply.status.code).to.equal(200);
+        expect(aliceQueryWriteAfterAliceWriteReply.entries?.length).to.equal(1);
+        expect(aliceQueryWriteAfterAliceWriteReply.entries![0].encodedData).to.equal(encodedData);
+
+        await expect(ArrayUtility.fromAsyncGenerator(blockstoreOfAliceOfDataCid.db.keys())).to.eventually.eql([ dataCid ]);
+
+        // bob learns of the CID of data of alice and tries to gain unauthorized access by referencing it in his own DWN
+        const bobAssociateData = await TestDataGenerator.generateRecordsWrite({
+          requester : bob,
+          dataCid,
+          dataSize  : 4
+        });
+        const bobAssociateReply = await dwn.processMessage(bob.did, bobAssociateData.message, bobAssociateData.dataStream);
+        expect(bobAssociateReply.status.code).to.equal(400); // expecting an error
+        expect(bobAssociateReply.status.detail).to.contain(DwnErrorCode.RecordsWriteMissingDataStream);
+
+        const aliceQueryWriteAfterBobAssociateData = await TestDataGenerator.generateRecordsQuery({
+          requester : alice,
+          filter    : { recordId: aliceWriteData.message.recordId }
+        });
+        const aliceQueryWriteAfterBobAssociateReply = await dwn.processMessage(alice.did, aliceQueryWriteAfterBobAssociateData.message);
+        expect(aliceQueryWriteAfterBobAssociateReply.status.code).to.equal(200);
+        expect(aliceQueryWriteAfterBobAssociateReply.entries?.length).to.equal(1);
+        expect(aliceQueryWriteAfterBobAssociateReply.entries![0].encodedData).to.equal(encodedData);
+
+        // verify that bob has not gained access to alice's data
+        const bobQueryAssociateAfterBobAssociateData = await TestDataGenerator.generateRecordsQuery({
+          requester : bob,
+          filter    : { recordId: bobAssociateData.message.recordId }
+        });
+        const bobQueryAssociateAfterBobAssociateReply = await dwn.processMessage(bob.did, bobQueryAssociateAfterBobAssociateData.message);
+        expect(bobQueryAssociateAfterBobAssociateReply.status.code).to.equal(200);
+        expect(bobQueryAssociateAfterBobAssociateReply.entries?.length).to.equal(0);
+
+        // verify that bob's blockstore does not contain alice's data
+        await expect(ArrayUtility.fromAsyncGenerator(blockstoreOfAliceOfDataCid.db.keys())).to.eventually.eql([ dataCid ]);
+        await expect(ArrayUtility.fromAsyncGenerator(blockstoreOfBobOfDataCid.db.keys())).to.eventually.eql([ ]);
+      });
     });
   });
 
diff --git a/tests/store/data-store.spec.ts b/tests/store/data-store.spec.ts
index 1046cf018..124c71829 100644
--- a/tests/store/data-store.spec.ts
+++ b/tests/store/data-store.spec.ts
@@ -1,7 +1,7 @@
 import chaiAsPromised from 'chai-as-promised';
 import chai, { expect } from 'chai';
 
-import { asyncGeneratorToArray } from '../../src/utils/array.js';
+import { ArrayUtility } from '../../src/utils/array.js';
 import { Cid } from '../../src/utils/cid.js';
 import { DataStoreLevel } from '../../src/store/data-store-level.js';
 import { DataStream } from '../../src/index.js';
@@ -88,13 +88,13 @@ describe('DataStore Test Suite', () => {
       const messageCid = await TestDataGenerator.randomCborSha256Cid();
       const randomCid = await TestDataGenerator.randomCborSha256Cid();
 
-      const keysBeforeAssociate = await asyncGeneratorToArray(store.blockstore.db.keys());
+      const keysBeforeAssociate = await ArrayUtility.fromAsyncGenerator(store.blockstore.db.keys());
       expect(keysBeforeAssociate.length).to.equal(0);
 
       const result = await store.associate(tenant, messageCid, randomCid);
       expect(result).to.be.undefined;
 
-      const keysAfterAssociate = await asyncGeneratorToArray(store.blockstore.db.keys());
+      const keysAfterAssociate = await ArrayUtility.fromAsyncGenerator(store.blockstore.db.keys());
       expect(keysAfterAssociate.length).to.equal(0);
     });
 
@@ -109,13 +109,13 @@ describe('DataStore Test Suite', () => {
       const { dataCid } = await store.put(tenant, messageCid, randomCid, dataStream);
       expect(dataCid).to.not.equal(randomCid);
 
-      const keysBeforeAssociate = await asyncGeneratorToArray(store.blockstore.db.keys());
+      const keysBeforeAssociate = await ArrayUtility.fromAsyncGenerator(store.blockstore.db.keys());
       expect(keysBeforeAssociate.length).to.equal(2);
 
       const result = await store.associate(tenant, messageCid, randomCid);
       expect(result).to.be.undefined;
 
-      const keysAfterAssociate = await asyncGeneratorToArray(store.blockstore.db.keys());
+      const keysAfterAssociate = await ArrayUtility.fromAsyncGenerator(store.blockstore.db.keys());
       expect(keysAfterAssociate.length).to.equal(2);
     });
 
@@ -129,14 +129,14 @@ describe('DataStore Test Suite', () => {
 
       await store.put(tenant, messageCid, dataCid, dataStream);
 
-      const keysBeforeDelete = await asyncGeneratorToArray(store.blockstore.db.keys());
+      const keysBeforeDelete = await ArrayUtility.fromAsyncGenerator(store.blockstore.db.keys());
       expect(keysBeforeDelete.length).to.equal(41);
 
       const result = (await store.associate(tenant, messageCid, dataCid))!;
       expect(result.dataCid).to.equal(dataCid);
       expect(result.dataSize).to.equal(10_000_000);
 
-      const keysAfterDelete = await asyncGeneratorToArray(store.blockstore.db.keys());
+      const keysAfterDelete = await ArrayUtility.fromAsyncGenerator(store.blockstore.db.keys());
       expect(keysAfterDelete.length).to.equal(41);
     });
   });
@@ -152,12 +152,12 @@ describe('DataStore Test Suite', () => {
 
       await store.put(tenant, messageCid, dataCid, dataStream);
 
-      const keysBeforeDelete = await asyncGeneratorToArray(store.blockstore.db.keys());
+      const keysBeforeDelete = await ArrayUtility.fromAsyncGenerator(store.blockstore.db.keys());
       expect(keysBeforeDelete.length).to.equal(41);
 
       await store.delete(tenant, messageCid, dataCid);
 
-      const keysAfterDelete = await asyncGeneratorToArray(store.blockstore.db.keys());
+      const keysAfterDelete = await ArrayUtility.fromAsyncGenerator(store.blockstore.db.keys());
       expect(keysAfterDelete.length).to.equal(0);
     });
   });
diff --git a/tests/store/index-level.spec.ts b/tests/store/index-level.spec.ts
index 5ef1ce756..f10c94a42 100644
--- a/tests/store/index-level.spec.ts
+++ b/tests/store/index-level.spec.ts
@@ -1,7 +1,7 @@
 import chaiAsPromised from 'chai-as-promised';
 import chai, { expect } from 'chai';
 
-import { asyncGeneratorToArray } from '../../src/utils/array.js';
+import { ArrayUtility } from '../../src/utils/array.js';
 import { IndexLevel } from '../../src/store/index-level.js';
 import { Temporal } from '@js-temporal/polyfill';
 import { v4 as uuid } from 'uuid';
@@ -32,7 +32,7 @@ describe('Index Level', () => {
         'c'         : 'd'
       });
 
-      const keys = await asyncGeneratorToArray(index.db.keys());
+      const keys = await ArrayUtility.fromAsyncGenerator(index.db.keys());
       expect(keys.length).to.equal(4);
     });
 
diff --git a/tests/utils/comparer.ts b/tests/utils/comparer.ts
deleted file mode 100644
index 2af3360ab..000000000
--- a/tests/utils/comparer.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-/**
- * Class containing data comparison utilities.
- */
-export class Comparer {
-  /**
-   * Returns `true` if content of the two given byte arrays are equal; `false` otherwise.
-   */
-  public static byteArraysEqual(array1: Uint8Array, array2:Uint8Array): boolean {
-    const equal = array1.length === array2.length && array1.every((value, index) => value === array2[index]);
-    return equal;
-  }
-}
\ No newline at end of file
diff --git a/tests/utils/encryption.spec.ts b/tests/utils/encryption.spec.ts
index 546c3d147..f6341cea7 100644
--- a/tests/utils/encryption.spec.ts
+++ b/tests/utils/encryption.spec.ts
@@ -1,4 +1,4 @@
-import { Comparer } from '../utils/comparer.js';
+import { ArrayUtility } from '../../src/utils/array.js';
 import { DataStream } from '../../src/index.js';
 import { Encryption } from '../../src/utils/encryption.js';
 import { expect } from 'chai';
@@ -20,7 +20,7 @@ describe('Encryption', () => {
       const plaintextStream = await Encryption.aes256CtrDecrypt(key, initializationVector, cipherStream);
       const plaintextBytes = await DataStream.toBytes(plaintextStream);
 
-      expect(Comparer.byteArraysEqual(inputBytes, plaintextBytes)).to.be.true;
+      expect(ArrayUtility.byteArraysEqual(inputBytes, plaintextBytes)).to.be.true;
     });
 
     it('should emit error on encrypt if the plaintext data stream emits an error', async () => {
@@ -115,7 +115,7 @@ describe('Encryption', () => {
       const decryptionInput = { privateKey, ...encryptionOutput };
       const decryptedPlaintext = await Encryption.eciesSecp256k1Decrypt(decryptionInput);
 
-      expect(Comparer.byteArraysEqual(originalPlaintext, decryptedPlaintext)).to.be.true;
+      expect(ArrayUtility.byteArraysEqual(originalPlaintext, decryptedPlaintext)).to.be.true;
     });
   });
 });
diff --git a/tests/utils/secp256k1.spec.ts b/tests/utils/secp256k1.spec.ts
index 81a5ae001..dc77505d6 100644
--- a/tests/utils/secp256k1.spec.ts
+++ b/tests/utils/secp256k1.spec.ts
@@ -1,5 +1,5 @@
+import { ArrayUtility } from '../../src/utils/array.js';
 import { base64url } from 'multiformats/bases/base64';
-import { Comparer } from './comparer.js';
 import { DwnErrorCode } from '../../src/core/dwn-error.js';
 import { expect } from 'chai';
 import { Secp256k1 } from '../../src/utils/secp256k1.js';
@@ -51,7 +51,7 @@ describe('Secp256k1', () => {
       const derivedPublicKey = Secp256k1.deriveChildPublicKey(publicKey, tweakInput);
 
       const publicKeyFromDerivedPrivateKey = await Secp256k1.getPublicKey(derivedPrivateKey);
-      expect(Comparer.byteArraysEqual(derivedPublicKey, publicKeyFromDerivedPrivateKey)).to.be.true;
+      expect(ArrayUtility.byteArraysEqual(derivedPublicKey, publicKeyFromDerivedPrivateKey)).to.be.true;
     });
   });
 
@@ -67,17 +67,17 @@ describe('Secp256k1', () => {
       const publicKeyG = await Secp256k1.derivePublicKey(publicKey, fullPathToG);
       const publicKeyD = await Secp256k1.derivePublicKey(publicKey, fullPathToD);
       const publicKeyGFromD = await Secp256k1.derivePublicKey(publicKeyD, relativePathFromDToG);
-      expect(Comparer.byteArraysEqual(publicKeyG, publicKeyGFromD)).to.be.true;
+      expect(ArrayUtility.byteArraysEqual(publicKeyG, publicKeyGFromD)).to.be.true;
 
       // testing private key derivation from different ancestor in the same chain
       const privateKeyG = await Secp256k1.derivePrivateKey(privateKey, fullPathToG);
       const privateKeyD = await Secp256k1.derivePrivateKey(privateKey, fullPathToD);
       const privateKeyGFromD = await Secp256k1.derivePrivateKey(privateKeyD, relativePathFromDToG);
-      expect(Comparer.byteArraysEqual(privateKeyG, privateKeyGFromD)).to.be.true;
+      expect(ArrayUtility.byteArraysEqual(privateKeyG, privateKeyGFromD)).to.be.true;
 
       // testing that the derived private key matches up with the derived public key
       const publicKeyGFromPrivateKeyG = await Secp256k1.getPublicKey(privateKeyG);
-      expect(Comparer.byteArraysEqual(publicKeyGFromPrivateKeyG, publicKeyG)).to.be.true;
+      expect(ArrayUtility.byteArraysEqual(publicKeyGFromPrivateKeyG, publicKeyG)).to.be.true;
     });
 
     it('should derive the same public key using either the private or public counterpart of the same key pair', async () => {
@@ -87,7 +87,7 @@ describe('Secp256k1', () => {
 
       const derivedKeyFromPublicKey = await Secp256k1.derivePublicKey(publicKey, path);
       const derivedKeyFromPrivateKey = await Secp256k1.derivePublicKey(privateKey, path);
-      expect(Comparer.byteArraysEqual(derivedKeyFromPublicKey, derivedKeyFromPrivateKey)).to.be.true;
+      expect(ArrayUtility.byteArraysEqual(derivedKeyFromPublicKey, derivedKeyFromPrivateKey)).to.be.true;
     });
 
     it('should derive the same public key using either the private or public counterpart of the same key pair', async () => {