Repository: paritytech/ink
Pull request #447 (2020-06-13 18:53:58)

Integrate new Key and KeyPtr types into rest of ink!
This integrates the new `Key` and `KeyPtr` primitives that have been introduced to the `ink_primitives` crate in [this PR](https://github.com/paritytech/ink/pull/433) with the rest of the ink! codebase.

Also it removes the deprecated `Key` and `KeyPtr` abstractions.

codecov-commenter: # [Codecov](https://codecov.io/gh/paritytech/ink/pull/447?src=pr&el=h1) Report
> Merging [#447](https://codecov.io/gh/paritytech/ink/pull/447?src=pr&el=desc) into [master](https://codecov.io/gh/paritytech/ink/commit/2021becfd15be0ca9cd0ff2f3d4d62566b65a8d5&el=desc) will **decrease** coverage by `0.01%`.
> The diff coverage is `79.31%`.

[![Impacted file tree graph](https://codecov.io/gh/paritytech/ink/pull/447/graphs/tree.svg?width=650&height=150&src=pr&token=tYyVaCZb7o)](https://codecov.io/gh/paritytech/ink/pull/447?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #447      +/-   ##
==========================================
- Coverage   86.37%   86.35%   -0.02%     
==========================================
  Files         110      107       -3     
  Lines        4249     4156      -93     
==========================================
- Hits         3670     3589      -81     
+ Misses        579      567      -12     
```


| [Impacted Files](https://codecov.io/gh/paritytech/ink/pull/447?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [core/src/storage2/alloc/allocation.rs](https://codecov.io/gh/paritytech/ink/pull/447/diff?src=pr&el=tree#diff-Y29yZS9zcmMvc3RvcmFnZTIvYWxsb2MvYWxsb2NhdGlvbi5ycw==) | `100.00% <ø> (ø)` | |
| [core/src/storage2/alloc/boxed/tests.rs](https://codecov.io/gh/paritytech/ink/pull/447/diff?src=pr&el=tree#diff-Y29yZS9zcmMvc3RvcmFnZTIvYWxsb2MvYm94ZWQvdGVzdHMucnM=) | `100.00% <ø> (ø)` | |
| [core/src/storage2/alloc/tests.rs](https://codecov.io/gh/paritytech/ink/pull/447/diff?src=pr&el=tree#diff-Y29yZS9zcmMvc3RvcmFnZTIvYWxsb2MvdGVzdHMucnM=) | `100.00% <ø> (ø)` | |
| [core/src/storage2/collections/bitstash/tests.rs](https://codecov.io/gh/paritytech/ink/pull/447/diff?src=pr&el=tree#diff-Y29yZS9zcmMvc3RvcmFnZTIvY29sbGVjdGlvbnMvYml0c3Rhc2gvdGVzdHMucnM=) | `100.00% <ø> (ø)` | |
| [core/src/storage2/collections/bitvec/tests.rs](https://codecov.io/gh/paritytech/ink/pull/447/diff?src=pr&el=tree#diff-Y29yZS9zcmMvc3RvcmFnZTIvY29sbGVjdGlvbnMvYml0dmVjL3Rlc3RzLnJz) | `100.00% <ø> (ø)` | |
| [core/src/storage2/collections/smallvec/tests.rs](https://codecov.io/gh/paritytech/ink/pull/447/diff?src=pr&el=tree#diff-Y29yZS9zcmMvc3RvcmFnZTIvY29sbGVjdGlvbnMvc21hbGx2ZWMvdGVzdHMucnM=) | `100.00% <ø> (ø)` | |
| [core/src/storage2/collections/stash/tests.rs](https://codecov.io/gh/paritytech/ink/pull/447/diff?src=pr&el=tree#diff-Y29yZS9zcmMvc3RvcmFnZTIvY29sbGVjdGlvbnMvc3Rhc2gvdGVzdHMucnM=) | `100.00% <ø> (ø)` | |
| [core/src/storage2/collections/vec/tests.rs](https://codecov.io/gh/paritytech/ink/pull/447/diff?src=pr&el=tree#diff-Y29yZS9zcmMvc3RvcmFnZTIvY29sbGVjdGlvbnMvdmVjL3Rlc3RzLnJz) | `100.00% <ø> (ø)` | |
| [core/src/storage2/memory.rs](https://codecov.io/gh/paritytech/ink/pull/447/diff?src=pr&el=tree#diff-Y29yZS9zcmMvc3RvcmFnZTIvbWVtb3J5LnJz) | `100.00% <ø> (ø)` | |
| [core/src/storage2/pack.rs](https://codecov.io/gh/paritytech/ink/pull/447/diff?src=pr&el=tree#diff-Y29yZS9zcmMvc3RvcmFnZTIvcGFjay5ycw==) | `100.00% <ø> (ø)` | |
| ... and [19 more](https://codecov.io/gh/paritytech/ink/pull/447/diff?src=pr&el=tree-more) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/paritytech/ink/pull/447?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/paritytech/ink/pull/447?src=pr&el=footer). Last update [2021bec...e198e62](https://codecov.io/gh/paritytech/ink/pull/447?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/abi/src/layout2/mod.rs b/abi/src/layout2/mod.rs
index b48aaca3fb..6d27dc3f4a 100644
--- a/abi/src/layout2/mod.rs
+++ b/abi/src/layout2/mod.rs
@@ -63,11 +63,19 @@ pub struct LayoutKey {
     key: [u8; 32],
 }
 
+impl<'a> From<&'a Key> for LayoutKey {
+    fn from(key: &'a Key) -> Self {
+        Self {
+            key: key.to_bytes(),
+        }
+    }
+}
+
 impl From<Key> for LayoutKey {
     fn from(key: Key) -> Self {
-        let mut arr = [0x00; 32];
-        arr.copy_from_slice(key.as_bytes());
-        Self { key: arr }
+        Self {
+            key: key.to_bytes(),
+        }
     }
 }
 
diff --git a/core/src/env/api.rs b/core/src/env/api.rs
index 93b24e1216..aa00a738a2 100644
--- a/core/src/env/api.rs
+++ b/core/src/env/api.rs
@@ -209,7 +209,7 @@ where
 }
 
 /// Writes the value to the contract storage under the given key.
-pub fn set_contract_storage<V>(key: Key, value: &V)
+pub fn set_contract_storage<V>(key: &Key, value: &V)
 where
     V: scale::Encode,
 {
@@ -223,7 +223,7 @@ where
 /// # Errors
 ///
 /// - If the decoding of the typed value failed
-pub fn get_contract_storage<R>(key: Key) -> Option<Result<R>>
+pub fn get_contract_storage<R>(key: &Key) -> Option<Result<R>>
 where
     R: scale::Decode,
 {
@@ -233,7 +233,7 @@ where
 }
 
 /// Clears the contract's storage key entry.
-pub fn clear_contract_storage(key: Key) {
+pub fn clear_contract_storage(key: &Key) {
     <EnvInstance as OnInstance>::on_instance(|instance| {
         Env::clear_contract_storage(instance, key)
     })
diff --git a/core/src/env/backend.rs b/core/src/env/backend.rs
index 17952f35ad..cb63b11b97 100644
--- a/core/src/env/backend.rs
+++ b/core/src/env/backend.rs
@@ -28,7 +28,7 @@ use ink_primitives::Key;
 /// Environmental contract functionality that does not require `EnvTypes`.
 pub trait Env {
     /// Writes the value to the contract storage under the given key.
-    fn set_contract_storage<V>(&mut self, key: Key, value: &V)
+    fn set_contract_storage<V>(&mut self, key: &Key, value: &V)
     where
         V: scale::Encode;
 
@@ -37,12 +37,12 @@ pub trait Env {
     /// # Errors
     ///
     /// - If the decoding of the typed value failed
-    fn get_contract_storage<R>(&mut self, key: Key) -> Option<Result<R>>
+    fn get_contract_storage<R>(&mut self, key: &Key) -> Option<Result<R>>
     where
         R: scale::Decode;
 
     /// Clears the contract's storage key entry.
-    fn clear_contract_storage(&mut self, key: Key);
+    fn clear_contract_storage(&mut self, key: &Key);
 
     /// Returns the value from the *runtime* storage at the position of the key if any.
     ///
diff --git a/core/src/env/engine/off_chain/impls.rs b/core/src/env/engine/off_chain/impls.rs
index 932dde8b49..04ff3f8fa6 100644
--- a/core/src/env/engine/off_chain/impls.rs
+++ b/core/src/env/engine/off_chain/impls.rs
@@ -60,27 +60,27 @@ impl EnvInstance {
 }
 
 impl Env for EnvInstance {
-    fn set_contract_storage<V>(&mut self, key: Key, value: &V)
+    fn set_contract_storage<V>(&mut self, key: &Key, value: &V)
     where
         V: scale::Encode,
     {
         self.callee_account_mut()
-            .set_storage(key, value)
+            .set_storage(*key, value)
             .expect("callee account is not a smart contract");
     }
 
-    fn get_contract_storage<R>(&mut self, key: Key) -> Option<Result<R>>
+    fn get_contract_storage<R>(&mut self, key: &Key) -> Option<Result<R>>
     where
         R: scale::Decode,
     {
         self.callee_account()
-            .get_storage::<R>(key)
+            .get_storage::<R>(*key)
             .map(|result| result.map_err(Into::into))
     }
 
-    fn clear_contract_storage(&mut self, key: Key) {
+    fn clear_contract_storage(&mut self, key: &Key) {
         self.callee_account_mut()
-            .clear_storage(key)
+            .clear_storage(*key)
             .expect("callee account is not a smart contract");
     }
 
diff --git a/core/src/env/engine/on_chain/impls.rs b/core/src/env/engine/on_chain/impls.rs
index c41a69f659..d2954a2b31 100644
--- a/core/src/env/engine/on_chain/impls.rs
+++ b/core/src/env/engine/on_chain/impls.rs
@@ -132,7 +132,7 @@ impl EnvInstance {
 }
 
 impl Env for EnvInstance {
-    fn set_contract_storage<V>(&mut self, key: Key, value: &V)
+    fn set_contract_storage<V>(&mut self, key: &Key, value: &V)
     where
         V: scale::Encode,
     {
@@ -140,7 +140,7 @@ impl Env for EnvInstance {
         ext::set_storage(key.as_bytes(), &self.buffer[..]);
     }
 
-    fn get_contract_storage<R>(&mut self, key: Key) -> Option<Result<R>>
+    fn get_contract_storage<R>(&mut self, key: &Key) -> Option<Result<R>>
     where
         R: scale::Decode,
     {
@@ -150,7 +150,7 @@ impl Env for EnvInstance {
         Some(self.decode_scratch_buffer().map_err(Into::into))
     }
 
-    fn clear_contract_storage(&mut self, key: Key) {
+    fn clear_contract_storage(&mut self, key: &Key) {
         ext::clear_storage(key.as_bytes())
     }
 
diff --git a/core/src/storage2/alloc/allocation.rs b/core/src/storage2/alloc/allocation.rs
index 35c010b1f1..1b8678cd62 100644
--- a/core/src/storage2/alloc/allocation.rs
+++ b/core/src/storage2/alloc/allocation.rs
@@ -83,6 +83,6 @@ fn get_works() {
             \xB9\x6D\xF9\x51\xB6\x1D\x4F\x3B\
             \x4E\x75\xAC\x3B\x14\x57\x47\x96",
     ];
-    assert_eq!(DynamicAllocation(0).key(), Key(*expected_keys[0]));
-    assert_eq!(DynamicAllocation(1).key(), Key(*expected_keys[1]));
+    assert_eq!(DynamicAllocation(0).key(), Key::from(*expected_keys[0]));
+    assert_eq!(DynamicAllocation(1).key(), Key::from(*expected_keys[1]));
 }
diff --git a/core/src/storage2/alloc/init.rs b/core/src/storage2/alloc/init.rs
index e21e4fd06e..ee0264275d 100644
--- a/core/src/storage2/alloc/init.rs
+++ b/core/src/storage2/alloc/init.rs
@@ -115,7 +115,7 @@ impl DynamicAllocatorState {
                 // instance back onto the contract storage.
                 push_spread_root::<DynamicAllocator>(
                     &allocator,
-                    &Key(DYNAMIC_ALLOCATOR_KEY_OFFSET),
+                    &Key::from(DYNAMIC_ALLOCATOR_KEY_OFFSET),
                 );
                 // Prevent calling `drop` on the dynamic storage allocator
                 // instance since this would clear all contract storage
@@ -155,7 +155,7 @@ impl DynamicAllocatorState {
                 result
             }
             DynamicAllocatorState::UninitCall => {
-                let mut allocator = pull_spread_root::<DynamicAllocator>(&Key(
+                let mut allocator = pull_spread_root::<DynamicAllocator>(&Key::from(
                     DYNAMIC_ALLOCATOR_KEY_OFFSET,
                 ));
                 let result = f(&mut allocator);
diff --git a/core/src/storage2/lazy/lazy_array.rs b/core/src/storage2/lazy/lazy_array.rs
index e10970e4d7..8187a9a2b4 100644
--- a/core/src/storage2/lazy/lazy_array.rs
+++ b/core/src/storage2/lazy/lazy_array.rs
@@ -341,7 +341,7 @@ where
         } else {
             // The type does not require deep clean-up so we can simply clean-up
             // its associated storage cell and be done without having to load it first.
-            crate::env::clear_contract_storage(root_key);
+            crate::env::clear_contract_storage(&root_key);
         }
     }
 }
@@ -426,15 +426,15 @@ where
     const FOOTPRINT: u64 = <N as Unsigned>::U64;
 
     fn pull_spread(ptr: &mut KeyPtr) -> Self {
-        Self::lazy(ExtKeyPtr::next_for::<Self>(ptr))
+        Self::lazy(*ExtKeyPtr::next_for::<Self>(ptr))
     }
 
     fn push_spread(&self, ptr: &mut KeyPtr) {
         let offset_key = ExtKeyPtr::next_for::<Self>(ptr);
         for (index, entry) in self.cached_entries().iter().enumerate() {
             if let Some(entry) = entry {
-                let root_key = offset_key + index as u64;
-                entry.push_packed_root(&root_key);
+                let key = offset_key + (index as u64);
+                entry.push_packed_root(&key);
             }
         }
     }
@@ -457,7 +457,7 @@ where
         if at >= self.capacity() {
             return None
         }
-        self.key.map(|key| key + at as u64)
+        self.key.as_ref().map(|key| key + at as u64)
     }
 }
 
@@ -651,7 +651,7 @@ mod tests {
 
     #[test]
     fn lazy_works() {
-        let key = Key([0x42; 32]);
+        let key = Key::from([0x42; 32]);
         let larray = <LazyArray<u8, U4>>::lazy(key);
         // Key must be Some.
         assert_eq!(larray.key(), Some(&key));
@@ -870,7 +870,7 @@ mod tests {
             // Push the lazy index map onto the contract storage and then load
             // another instance of it from the contract stoarge.
             // Then: Compare both instances to be equal.
-            let root_key = Key([0x42; 32]);
+            let root_key = Key::from([0x42; 32]);
             SpreadLayout::push_spread(&larray, &mut KeyPtr::from(root_key));
             let larray2 = <LazyArray<u8, U4> as SpreadLayout>::pull_spread(
                 &mut KeyPtr::from(root_key),
diff --git a/core/src/storage2/lazy/lazy_cell.rs b/core/src/storage2/lazy/lazy_cell.rs
index 8ce6217491..72c2ee8af9 100644
--- a/core/src/storage2/lazy/lazy_cell.rs
+++ b/core/src/storage2/lazy/lazy_cell.rs
@@ -88,16 +88,16 @@ fn debug_impl_works() {
         format!("{:?}", &c2),
         "LazyCell { key: None, cache: Some(Entry { value: Some(42), state: Mutated }) }",
     );
-    let c3 = <LazyCell<i32>>::lazy(Key([0x00; 32]));
+    let c3 = <LazyCell<i32>>::lazy(Key::from([0x00; 32]));
     assert_eq!(
         format!("{:?}", &c3),
         "LazyCell { \
-            key: Some(Key(\
-                0x00_\
-                00000000_00000000_\
-                00000000_00000000_\
-                00000000_00000000_\
-                00000000_000000)), \
+            key: Some(Key(0x_\
+                0000000000000000_\
+                0000000000000000_\
+                0000000000000000_\
+                0000000000000000)\
+            ), \
             cache: None \
         }",
     );
@@ -138,7 +138,7 @@ where
     const FOOTPRINT: u64 = <T as SpreadLayout>::FOOTPRINT;
 
     fn pull_spread(ptr: &mut KeyPtr) -> Self {
-        Self::lazy(KeyPtr::next_for::<T>(ptr))
+        Self::lazy(*KeyPtr::next_for::<T>(ptr))
     }
 
     fn push_spread(&self, ptr: &mut KeyPtr) {
@@ -354,7 +354,7 @@ mod tests {
 
     #[test]
     fn lazy_works() {
-        let root_key = Key([0x42; 32]);
+        let root_key = Key::from([0x42; 32]);
         let cell = <LazyCell<u8>>::lazy(root_key);
         assert_eq!(cell.key(), Some(&root_key));
     }
@@ -362,7 +362,7 @@ mod tests {
     #[test]
     fn lazy_get_works() -> env::Result<()> {
         run_test::<env::DefaultEnvTypes, _>(|_| {
-            let cell = <LazyCell<u8>>::lazy(Key([0x42; 32]));
+            let cell = <LazyCell<u8>>::lazy(Key::from([0x42; 32]));
             let value = cell.get();
             // We do the normally unreachable check in order to have an easier
             // time finding the issue if the above execution did not panic.
@@ -387,7 +387,7 @@ mod tests {
             // Push `cell_a0` to the contract storage.
             // Then, pull `cell_a1` from the contract storage and check if it is
             // equal to `cell_a0`.
-            let root_key = Key([0x42; 32]);
+            let root_key = Key::from([0x42; 32]);
             SpreadLayout::push_spread(&cell_a0, &mut KeyPtr::from(root_key));
             let cell_a1 =
                 <LazyCell<u8> as SpreadLayout>::pull_spread(&mut KeyPtr::from(root_key));
diff --git a/core/src/storage2/lazy/lazy_hmap.rs b/core/src/storage2/lazy/lazy_hmap.rs
index 6141391fb7..dd87cbe5c6 100644
--- a/core/src/storage2/lazy/lazy_hmap.rs
+++ b/core/src/storage2/lazy/lazy_hmap.rs
@@ -195,7 +195,7 @@ where
     const FOOTPRINT: u64 = 1;
 
     fn pull_spread(ptr: &mut KeyPtr) -> Self {
-        Self::lazy(ExtKeyPtr::next_for::<Self>(ptr))
+        Self::lazy(*ExtKeyPtr::next_for::<Self>(ptr))
     }
 
     fn push_spread(&self, ptr: &mut KeyPtr) {
@@ -455,7 +455,7 @@ where
         } else {
             // The type does not require deep clean-up so we can simply clean-up
             // its associated storage cell and be done without having to load it first.
-            crate::env::clear_contract_storage(root_key);
+            crate::env::clear_contract_storage(&root_key);
         }
     }
 
@@ -605,7 +605,7 @@ mod tests {
 
     #[test]
     fn key_at_works() {
-        let key = Key([0x42; 32]);
+        let key = Key::from([0x42; 32]);
 
         // BLAKE2 256-bit hasher:
         let hmap1 = <LazyHashMap<i32, u8, Blake2x256Hasher>>::lazy(key);
@@ -618,20 +618,22 @@ mod tests {
         \x96\x65\x0E\xCD\x1F\x2C\xE8\x5D\
         \xBF\x7E\xC0\xFF\x16\x40\x8A\xD8\
         \x75\x88\xDE\x52\xF5\x8B\x99\xAF";
-        assert_eq!(hmap1.key_at(&0), Some(Key(*hmap1_at_0)));
+        assert_eq!(hmap1.key_at(&0), Some(Key::from(*hmap1_at_0)));
         // Same parameters must yield the same key:
         //
         // This tests an actual regression that happened because the
         // hash accumulator was not reset after a hash finalization.
         assert_cached_entries(&hmap1, &[]);
-        assert_eq!(hmap1.key_at(&0), Some(Key(*hmap1_at_0)));
+        assert_eq!(hmap1.key_at(&0), Some(Key::from(*hmap1_at_0)));
         assert_eq!(
             hmap1.key_at(&1),
-            Some(Key(*b"\
+            Some(Key::from(
+                *b"\
                 \x9A\x46\x1F\xB3\xA1\xC4\x20\xF8\
                 \xA0\xD9\xA7\x79\x2F\x07\xFB\x7D\
                 \x49\xDD\xAB\x08\x67\x90\x96\x15\
-                \xFB\x85\x36\x3B\x82\x94\x85\x3F"))
+                \xFB\x85\x36\x3B\x82\x94\x85\x3F"
+            ))
         );
         // SHA2 256-bit hasher:
         let hmap2 = <LazyHashMap<i32, u8, Sha2x256Hasher>>::lazy(key);
@@ -641,19 +643,23 @@ mod tests {
         assert_cached_entries(&hmap2, &[]);
         assert_eq!(
             hmap1.key_at(&0),
-            Some(Key(*b"\
+            Some(Key::from(
+                *b"\
                 \x67\x7E\xD3\xA4\x72\x2A\x83\x60\
                 \x96\x65\x0E\xCD\x1F\x2C\xE8\x5D\
                 \xBF\x7E\xC0\xFF\x16\x40\x8A\xD8\
-                \x75\x88\xDE\x52\xF5\x8B\x99\xAF"))
+                \x75\x88\xDE\x52\xF5\x8B\x99\xAF"
+            ))
         );
         assert_eq!(
             hmap1.key_at(&1),
-            Some(Key(*b"\
+            Some(Key::from(
+                *b"\
                 \x9A\x46\x1F\xB3\xA1\xC4\x20\xF8\
                 \xA0\xD9\xA7\x79\x2F\x07\xFB\x7D\
                 \x49\xDD\xAB\x08\x67\x90\x96\x15\
-                \xFB\x85\x36\x3B\x82\x94\x85\x3F"))
+                \xFB\x85\x36\x3B\x82\x94\x85\x3F"
+            ))
         );
     }
 
@@ -869,14 +875,14 @@ mod tests {
             // Push the lazy index map onto the contract storage and then load
             // another instance of it from the contract stoarge.
             // Then: Compare both instances to be equal.
-            let root_key = Key([0x42; 32]);
+            let root_key = Key::from([0x42; 32]);
             SpreadLayout::push_spread(&hmap, &mut KeyPtr::from(root_key));
             let hmap2 =
                 <LazyHashMap<i32, u8, Blake2x256Hasher> as SpreadLayout>::pull_spread(
                     &mut KeyPtr::from(root_key),
                 );
             assert_cached_entries(&hmap2, &[]);
-            assert_eq!(hmap2.key(), Some(&Key([0x42; 32])));
+            assert_eq!(hmap2.key(), Some(&Key::from([0x42; 32])));
             assert_eq!(hmap2.get(&1), Some(&b'A'));
             assert_eq!(hmap2.get(&2), Some(&b'B'));
             assert_eq!(hmap2.get(&3), None);
diff --git a/core/src/storage2/lazy/lazy_imap.rs b/core/src/storage2/lazy/lazy_imap.rs
index 6ac70df620..ff98fd8d5c 100644
--- a/core/src/storage2/lazy/lazy_imap.rs
+++ b/core/src/storage2/lazy/lazy_imap.rs
@@ -233,13 +233,13 @@ where
     const FOOTPRINT: u64 = 1_u64 << 32;
 
     fn pull_spread(ptr: &mut KeyPtr) -> Self {
-        Self::lazy(ExtKeyPtr::next_for::<Self>(ptr))
+        Self::lazy(*ExtKeyPtr::next_for::<Self>(ptr))
     }
 
     fn push_spread(&self, ptr: &mut KeyPtr) {
         let offset_key = ExtKeyPtr::next_for::<Self>(ptr);
         for (&index, entry) in self.entries().iter() {
-            let root_key = offset_key + index;
+            let root_key = offset_key + (index as u64);
             entry.push_packed_root(&root_key);
         }
     }
@@ -278,7 +278,7 @@ where
         } else {
             // The type does not require deep clean-up so we can simply clean-up
             // its associated storage cell and be done without having to load it first.
-            crate::env::clear_contract_storage(root_key);
+            crate::env::clear_contract_storage(&root_key);
         }
     }
 }
@@ -482,7 +482,7 @@ mod tests {
 
     #[test]
     fn lazy_works() {
-        let key = Key([0x42; 32]);
+        let key = Key::from([0x42; 32]);
         let imap = <LazyIndexMap<u8>>::lazy(key);
         // Key must be none.
         assert_eq!(imap.key(), Some(&key));
@@ -704,7 +704,7 @@ mod tests {
             // Push the lazy index map onto the contract storage and then load
             // another instance of it from the contract stoarge.
             // Then: Compare both instances to be equal.
-            let root_key = Key([0x42; 32]);
+            let root_key = Key::from([0x42; 32]);
             SpreadLayout::push_spread(&imap, &mut KeyPtr::from(root_key));
             let imap2 = <LazyIndexMap<u8> as SpreadLayout>::pull_spread(
                 &mut KeyPtr::from(root_key),
diff --git a/core/src/storage2/memory.rs b/core/src/storage2/memory.rs
index cf0f0b5081..f1af0b12cb 100644
--- a/core/src/storage2/memory.rs
+++ b/core/src/storage2/memory.rs
@@ -255,7 +255,7 @@ mod tests {
         let p1 = Memory::new((b'A', [0x00; 4], (true, 42)));
         assert_eq!(*p1, (b'A', [0x00; 4], (true, 42)));
         assert_ne!(p1, Default::default());
-        let root_key = Key([0x42; 32]);
+        let root_key = Key::from([0x42; 32]);
         SpreadLayout::push_spread(&p1, &mut KeyPtr::from(root_key));
         // Now load another instance of a pack from the same key and check
         // if both instances are equal:
@@ -281,7 +281,7 @@ mod tests {
             // Clearing a memory instance should have no effect on the underlying
             // contract storage. We can test this by pushing and pulling a storage
             // affecting entity in between on the same storage region:
-            let root_key = Key([0x42; 32]);
+            let root_key = Key::from([0x42; 32]);
             <i32 as SpreadLayout>::push_spread(&42, &mut KeyPtr::from(root_key));
             let loaded1 = <i32 as SpreadLayout>::pull_spread(&mut KeyPtr::from(root_key));
             assert_eq!(loaded1, 42);
diff --git a/core/src/storage2/pack.rs b/core/src/storage2/pack.rs
index 322c9d429c..46eddf087b 100644
--- a/core/src/storage2/pack.rs
+++ b/core/src/storage2/pack.rs
@@ -384,7 +384,7 @@ mod tests {
         run_test(|_| {
             let p1 = Pack::new((b'A', [0x00; 4], (true, 42)));
             assert_eq!(*p1, (b'A', [0x00; 4], (true, 42)));
-            let root_key = Key([0x42; 32]);
+            let root_key = Key::from([0x42; 32]);
             SpreadLayout::push_spread(&p1, &mut KeyPtr::from(root_key));
             // Now load another instance of a pack from the same key and check
             // if both instances are equal:
@@ -399,7 +399,7 @@ mod tests {
         run_test(|_| {
             let p1 = Pack::new((b'A', [0x00; 4], (true, 42)));
             assert_eq!(*p1, (b'A', [0x00; 4], (true, 42)));
-            let root_key = Key([0x42; 32]);
+            let root_key = Key::from([0x42; 32]);
             SpreadLayout::push_spread(&p1, &mut KeyPtr::from(root_key));
             // Now load another instance of a pack from the same key and check
             // if both instances are equal:
@@ -419,12 +419,12 @@ mod tests {
             // Push as spread, pull as packed:
             let p1 = Pack::new((b'A', [0x00; 4], (true, 42)));
             assert_eq!(*p1, (b'A', [0x00; 4], (true, 42)));
-            let root_key = Key([0x42; 32]);
+            let root_key = Key::from([0x42; 32]);
             SpreadLayout::push_spread(&p1, &mut KeyPtr::from(root_key));
             let p2 = pull_packed_root::<Pack<(u8, [i32; 4], (bool, i32))>>(&root_key);
             assert_eq!(p1, p2);
             // Push as packed, pull as spread:
-            let root_key2 = Key([0x43; 32]);
+            let root_key2 = Key::from([0x43; 32]);
             push_packed_root(&p2, &root_key2);
             let p3 = SpreadLayout::pull_spread(&mut KeyPtr::from(root_key2));
             assert_eq!(p2, p3);
diff --git a/core/src/storage2/traits/impls/prims.rs b/core/src/storage2/traits/impls/prims.rs
index 40791378db..11d1411afd 100644
--- a/core/src/storage2/traits/impls/prims.rs
+++ b/core/src/storage2/traits/impls/prims.rs
@@ -269,8 +269,8 @@ mod tests {
                     run_test(|| {
                         $({
                             let x: $name = $value;
-                            let key = Key([0x42; 32]);
-                            let key2 = Key([0x77; 32]);
+                            let key = Key::from([0x42; 32]);
+                            let key2 = Key::from([0x77; 32]);
                             push_spread_root(&x, &key);
                             let y: $name = pull_spread_root(&key);
                             assert_eq!(x, y);
@@ -288,7 +288,7 @@ mod tests {
                     run_test(|| {
                         $({
                             let x: $name = $value;
-                            let key = Key([0x42; 32]);
+                            let key = Key::from([0x42; 32]);
                             push_spread_root(&x, &key);
                             // Works since we just populated the storage.
                             let y: $name = pull_spread_root(&key);
diff --git a/core/src/storage2/traits/keyptr.rs b/core/src/storage2/traits/keyptr.rs
index 817c03da26..0731a46168 100644
--- a/core/src/storage2/traits/keyptr.rs
+++ b/core/src/storage2/traits/keyptr.rs
@@ -20,13 +20,13 @@ pub use ink_primitives::KeyPtr;
 pub trait ExtKeyPtr {
     /// Advances the key pointer by the same amount of the footprint of the
     /// generic type parameter of `T` and returns the old value.
-    fn next_for<T>(&mut self) -> Key
+    fn next_for<T>(&mut self) -> &Key
     where
         T: SpreadLayout;
 }
 
 impl ExtKeyPtr for KeyPtr {
-    fn next_for<T>(&mut self) -> Key
+    fn next_for<T>(&mut self) -> &Key
     where
         T: SpreadLayout,
     {
diff --git a/core/src/storage2/traits/layout/impls.rs b/core/src/storage2/traits/layout/impls.rs
index c8b8247d94..432185952d 100644
--- a/core/src/storage2/traits/layout/impls.rs
+++ b/core/src/storage2/traits/layout/impls.rs
@@ -138,7 +138,7 @@ where
     fn layout(key_ptr: &mut KeyPtr) -> Layout {
         let dispatch_key = key_ptr.advance_by(1);
         Layout::Enum(EnumLayout::new(
-            dispatch_key,
+            *dispatch_key,
             vec![
                 (
                     Discriminant::from(0),
@@ -161,7 +161,7 @@ where
     fn layout(key_ptr: &mut KeyPtr) -> Layout {
         let dispatch_key = key_ptr.advance_by(1);
         Layout::Enum(EnumLayout::new(
-            dispatch_key,
+            *dispatch_key,
             vec![
                 (
                     Discriminant::from(0),
diff --git a/core/src/storage2/traits/mod.rs b/core/src/storage2/traits/mod.rs
index 0a5089e281..90495ed31c 100644
--- a/core/src/storage2/traits/mod.rs
+++ b/core/src/storage2/traits/mod.rs
@@ -136,7 +136,7 @@ pub fn pull_packed_root<T>(root_key: &Key) -> T
 where
     T: PackedLayout,
 {
-    let mut entity = crate::env::get_contract_storage::<T>(*root_key)
+    let mut entity = crate::env::get_contract_storage::<T>(root_key)
         .expect("storage entry was empty")
         .expect("could not properly decode storage entry");
     <T as PackedLayout>::pull_packed(&mut entity, root_key);
@@ -159,7 +159,7 @@ where
     T: PackedLayout,
 {
     <T as PackedLayout>::push_packed(entity, root_key);
-    crate::env::set_contract_storage(*root_key, entity);
+    crate::env::set_contract_storage(root_key, entity);
 }
 
 /// Clears the entity from the contract storage using packed layout.
@@ -178,5 +178,5 @@ where
     T: PackedLayout,
 {
     <T as PackedLayout>::clear_packed(entity, root_key);
-    crate::env::clear_contract_storage(*root_key);
+    crate::env::clear_contract_storage(root_key);
 }
diff --git a/core/src/storage2/traits/optspec.rs b/core/src/storage2/traits/optspec.rs
index 066ea08451..8137f354c7 100644
--- a/core/src/storage2/traits/optspec.rs
+++ b/core/src/storage2/traits/optspec.rs
@@ -32,7 +32,7 @@ where
 {
     // In case the contract storage is occupied we handle
     // the Option<T> as if it was a T.
-    env::get_contract_storage::<()>(*root_key)
+    env::get_contract_storage::<()>(root_key)
         .map(|_| super::pull_spread_root::<T>(root_key))
 }
 
@@ -100,7 +100,7 @@ pub fn pull_packed_root_opt<T>(root_key: &Key) -> Option<T>
 where
     T: PackedLayout,
 {
-    match env::get_contract_storage::<T>(*root_key) {
+    match env::get_contract_storage::<T>(root_key) {
         Some(value) => {
             // In case the contract storage is occupied we handle
             // the Option<T> as if it was a T.
@@ -126,7 +126,7 @@ where
         }
         None => {
             // Clear the associated storage cell.
-            env::clear_contract_storage(*root_key);
+            env::clear_contract_storage(root_key);
         }
     }
 }
diff --git a/lang/macro/src/codegen/abi.rs b/lang/macro/src/codegen/abi.rs
index 2e897b8502..6d6077dfda 100644
--- a/lang/macro/src/codegen/abi.rs
+++ b/lang/macro/src/codegen/abi.rs
@@ -273,7 +273,7 @@ impl GenerateAbi<'_> {
         let contract_ident = &self.contract.storage.ident;
         quote! {
             <#contract_ident as ::ink_core::storage2::traits::StorageLayout>::layout(
-                &mut ::ink_primitives::KeyPtr::from(::ink_primitives::Key([0x00; 32]))
+                &mut ::ink_primitives::KeyPtr::from(::ink_primitives::Key::from([0x00; 32]))
             )
         }
     }
diff --git a/lang/src/dispatcher.rs b/lang/src/dispatcher.rs
index 0baca8540e..715d87b4ba 100644
--- a/lang/src/dispatcher.rs
+++ b/lang/src/dispatcher.rs
@@ -157,7 +157,7 @@ where
         let args = <M as FnInput>::Input::decode(&mut &data.params()[..])
             .map_err(|_| DispatchError::InvalidParameters)?;
         alloc::initialize(ContractPhase::Call);
-        let root_key = Key([0x00; 32]);
+        let root_key = Key::from([0x00; 32]);
         let state =
             ManuallyDrop::new(pull_spread_root::<<M as FnState>::State>(&root_key));
         let result = <M as MessageRef>::CALLABLE(&state, args);
@@ -195,7 +195,7 @@ where
         let args = <M as FnInput>::Input::decode(&mut &data.params()[..])
             .map_err(|_| DispatchError::InvalidParameters)?;
         alloc::initialize(ContractPhase::Call);
-        let root_key = Key([0x00; 32]);
+        let root_key = Key::from([0x00; 32]);
         let mut state =
             ManuallyDrop::new(pull_spread_root::<<M as FnState>::State>(&root_key));
         let result = <M as MessageMut>::CALLABLE(&mut state, args);
@@ -234,7 +234,7 @@ where
         let args = <M as FnInput>::Input::decode(&mut &data.params()[..])
             .map_err(|_| DispatchError::InvalidParameters)?;
         alloc::initialize(ContractPhase::Deploy);
-        let root_key = Key([0x00; 32]);
+        let root_key = Key::from([0x00; 32]);
         let state = ManuallyDrop::new(<M as Constructor>::CALLABLE(args));
         push_spread_root::<<M as FnState>::State>(&state, &root_key);
         alloc::finalize();
diff --git a/primitives/benches/bench.rs b/primitives/benches/bench.rs
index a7fbc39a8a..7dad40e61e 100644
--- a/primitives/benches/bench.rs
+++ b/primitives/benches/bench.rs
@@ -20,41 +20,26 @@ use criterion::{
 };
 use ink_primitives::{
     Key,
-    Key2,
     KeyPtr,
-    KeyPtr2,
 };
 
 criterion_group!(
     bench_key,
     bench_key_add_assign_u64,
-    bench_key2_add_assign_u64,
-    bench_key2_add_assign_u64_one_ofvl,
-    bench_key2_add_assign_u64_two_ofvls,
-    bench_key2_add_assign_u64_three_ofvls,
-    bench_key2_add_assign_u64_wrap,
+    bench_key_add_assign_u64_one_ofvl,
+    bench_key_add_assign_u64_two_ofvls,
+    bench_key_add_assign_u64_three_ofvls,
+    bench_key_add_assign_u64_wrap,
 );
 criterion_group!(
     bench_key_ptr,
     bench_key_ptr_advance_by,
-    bench_key_ptr2_advance_by,
     bench_key_ptr_advance_by_repeat,
-    bench_key_ptr2_advance_by_repeat,
 );
-criterion_main!(bench_key, bench_key_ptr,);
+criterion_main!(bench_key, bench_key_ptr);
 
 fn bench_key_add_assign_u64(c: &mut Criterion) {
-    let key = Key([0x00; 32]);
-    c.bench_function("Key::add_assign(u64)", |b| {
-        b.iter(|| {
-            let mut copy = black_box(key);
-            let _ = black_box(copy += 1u64);
-        })
-    });
-}
-
-fn bench_key2_add_assign_u64(c: &mut Criterion) {
-    let key = Key2::from([0x00; 32]);
+    let key = Key::from([0x00; 32]);
     c.bench_function("Key2::add_assign(u64)", |b| {
         b.iter(|| {
             let mut copy = black_box(key);
@@ -63,8 +48,8 @@ fn bench_key2_add_assign_u64(c: &mut Criterion) {
     });
 }
 
-fn bench_key2_add_assign_u64_one_ofvl(c: &mut Criterion) {
-    let key = Key2::from([
+fn bench_key_add_assign_u64_one_ofvl(c: &mut Criterion) {
+    let key = Key::from([
         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
         0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -77,8 +62,8 @@ fn bench_key2_add_assign_u64_one_ofvl(c: &mut Criterion) {
     });
 }
 
-fn bench_key2_add_assign_u64_two_ofvls(c: &mut Criterion) {
-    let key = Key2::from([
+fn bench_key_add_assign_u64_two_ofvls(c: &mut Criterion) {
+    let key = Key::from([
         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
         0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
         0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -91,8 +76,8 @@ fn bench_key2_add_assign_u64_two_ofvls(c: &mut Criterion) {
     });
 }
 
-fn bench_key2_add_assign_u64_three_ofvls(c: &mut Criterion) {
-    let key = Key2::from([
+fn bench_key_add_assign_u64_three_ofvls(c: &mut Criterion) {
+    let key = Key::from([
         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
         0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -105,8 +90,8 @@ fn bench_key2_add_assign_u64_three_ofvls(c: &mut Criterion) {
     });
 }
 
-fn bench_key2_add_assign_u64_wrap(c: &mut Criterion) {
-    let key = Key2::from([0xFF; 32]);
+fn bench_key_add_assign_u64_wrap(c: &mut Criterion) {
+    let key = Key::from([0xFF; 32]);
     c.bench_function("Key2::add_assign(u64) - wrap", |b| {
         b.iter(|| {
             let mut copy = black_box(key);
@@ -116,38 +101,18 @@ fn bench_key2_add_assign_u64_wrap(c: &mut Criterion) {
 }
 
 fn bench_key_ptr_advance_by(c: &mut Criterion) {
-    let key = Key([0x00; 32]);
-    c.bench_function("KeyPtr::advance_by copy", |b| {
-        b.iter(|| {
-            let mut key_ptr = KeyPtr::from(key.clone());
-            let _ = black_box(key_ptr.advance_by(1));
-        })
-    });
-}
-
-fn bench_key_ptr2_advance_by(c: &mut Criterion) {
-    let key = Key2::from([0x00; 32]);
+    let key = Key::from([0x00; 32]);
     c.bench_function("KeyPtr2::advance_by copy", |b| {
         b.iter(|| {
-            let mut key_ptr = KeyPtr2::from(key.clone());
+            let mut key_ptr = KeyPtr::from(key.clone());
             let _ = black_box(key_ptr.advance_by(1));
         })
     });
 }
 
 fn bench_key_ptr_advance_by_repeat(c: &mut Criterion) {
-    let key = Key([0x00; 32]);
+    let key = Key::from([0x00; 32]);
     let mut key_ptr = KeyPtr::from(key.clone());
-    c.bench_function("KeyPtr::advance_by reuse", |b| {
-        b.iter(|| {
-            let _ = black_box(key_ptr.advance_by(1));
-        })
-    });
-}
-
-fn bench_key_ptr2_advance_by_repeat(c: &mut Criterion) {
-    let key = Key2::from([0x00; 32]);
-    let mut key_ptr = KeyPtr2::from(key.clone());
     c.bench_function("KeyPtr2::advance_by reuse", |b| {
         b.iter(|| {
             let _ = black_box(key_ptr.advance_by(1));
diff --git a/primitives/src/byte_utils.rs b/primitives/src/byte_utils.rs
deleted file mode 100644
index 058932fb61..0000000000
--- a/primitives/src/byte_utils.rs
+++ /dev/null
@@ -1,297 +0,0 @@
-// Copyright 2018-2020 Parity Technologies (UK) Ltd.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-//! Utilities to operate on byte or slices of bytes.
-
-/// Flips all bytes in the byte slice inplace.
-fn invert_bytes(bytes: &mut [u8]) {
-    for byte in bytes.iter_mut() {
-        *byte = !*byte;
-    }
-}
-
-/// Negate the given bytes inplace.
-///
-/// Interprets the bytes as big endian twos-complement number.
-pub fn negate_bytes(bytes: &mut [u8]) {
-    invert_bytes(bytes);
-    bytes_add_bytes(bytes, &[0x01]);
-}
-
-macro_rules! impl_slice_as_array {
-    ( $name:ident, $n:expr ) => {
-        /// Interprets the slice as exact size array if possible.
-        ///
-        /// Otherwise returns `None`.
-        pub fn $name<T>(slice: &[T]) -> Option<&[T; $n]> {
-            if slice.len() != $n {
-                return None
-            }
-            Some(unsafe { &*(slice.as_ptr() as *const [T; $n]) })
-        }
-    };
-}
-
-impl_slice_as_array!(slice4_as_array4, 4);
-impl_slice_as_array!(slice8_as_array8, 8);
-impl_slice_as_array!(slice16_as_array16, 16);
-
-/// Generic carry add/sub implementation
-/// between a byte slice and a byte.
-///
-/// Used by `bytes_add_byte` and `bytes_sub_byte`.
-///
-/// Returns `true` if there was an overflow.
-///
-/// # Note
-///
-/// Interprets the byte slices and the byte
-/// as big-endian twos-complement numbers.
-///
-/// # Panics
-///
-/// If `lhs` is an empty slice.
-fn bytes_ops_byte<F>(lhs: &mut [u8], rhs: u8, ops: F) -> bool
-where
-    F: Copy + Fn(u8, u8) -> (u8, bool),
-{
-    assert!(!lhs.is_empty());
-    let mut carry = rhs;
-    for lhs in lhs.iter_mut().rev() {
-        if carry == 0 {
-            return false
-        }
-        let (res, ovfl) = ops(*lhs, carry);
-        *lhs = res;
-        carry = u8::from(ovfl);
-    }
-    carry != 0
-}
-
-/// Generic carry-operation implementation for two byte slices
-/// of equal sizes.
-///
-/// # Note
-///
-/// Interprets the byte slices as big-endian twos-complement numbers.
-///
-/// # Panics
-///
-/// - If `lhs` and `rhs` do not have the same lengths.
-/// - If `lhs` or `rhs` is empty slice.
-fn bytes_ops_bytes_eq<F>(lhs: &mut [u8], rhs: &[u8], ops: F) -> bool
-where
-    F: Copy + Fn(u8, u8) -> (u8, bool),
-{
-    assert_eq!(lhs.len(), rhs.len());
-    assert!(!lhs.is_empty());
-    debug_assert!(!rhs.is_empty());
-    let mut carry = 0;
-    for (lhs, rhs) in lhs.iter_mut().zip(rhs.iter()).rev() {
-        let (res1, carry1) = ops(*lhs, carry);
-        let (res2, carry2) = ops(res1, *rhs);
-        debug_assert!(!(carry1 && carry2));
-        *lhs = res2;
-        carry = u8::from(carry1 || carry2);
-    }
-    carry != 0
-}
-
-/// Generic carry-operation implementation for two byte slices.
-///
-/// Used as underlying implementation of
-/// `bytes_add_bytes` and `bytes_sub_bytes`.
-///
-/// # Note
-///
-/// Interprets the byte slices as big-endian twos-complement numbers.
-///
-/// # Panics
-///
-/// - If the length of `lhs` is less than the length of `rhs`.
-/// - If `lhs` or `rhs` is empty slice.
-fn bytes_ops_bytes<F>(lhs: &mut [u8], rhs: &[u8], ops: F) -> bool
-where
-    F: Copy + Fn(u8, u8) -> (u8, bool),
-{
-    let lhs_len = lhs.len();
-    let rhs_len = rhs.len();
-    assert!(lhs_len > 0);
-    assert!(rhs_len > 0);
-    assert!(lhs_len >= rhs_len);
-    if rhs_len == 1 {
-        return bytes_ops_byte(lhs, rhs[0], ops)
-    }
-    if lhs_len == rhs_len {
-        return bytes_ops_bytes_eq(lhs, rhs, ops)
-    }
-    let (lhs_msb, lhs_lsb) = lhs.split_at_mut(lhs_len - rhs_len);
-    assert_eq!(lhs_lsb.len(), rhs_len);
-    let ovfl = bytes_ops_bytes_eq(lhs_lsb, rhs, ops);
-    if ovfl {
-        return bytes_ops_byte(lhs_msb, 0x1, ops)
-    }
-    false
-}
-
-/// Adds the given bytes slices inplace.
-///
-/// Returns `true` if there was an overflow.
-///
-/// # Note
-///
-/// Interprets the byte slices as big-endian twos-complement numbers.
-///
-/// # Panics
-///
-/// - If the length of `lhs` is less than the length of `rhs`.
-/// - If `lhs` or `rhs` is empty slice.
-pub fn bytes_add_bytes(lhs: &mut [u8], rhs: &[u8]) -> bool {
-    bytes_ops_bytes(lhs, rhs, u8::overflowing_add)
-}
-
-/// Subtracts the given bytes slices inplace.
-///
-/// Returns `true` if there was an overflow.
-///
-/// # Note
-///
-/// Interprets the byte slices as big-endian twos-complement numbers.
-///
-/// # Panics
-///
-/// - If the length of `lhs` is less than the length of `rhs`.
-/// - If `lhs` or `rhs` is empty slice.
-pub fn bytes_sub_bytes(lhs: &mut [u8], rhs: &[u8]) -> bool {
-    bytes_ops_bytes(lhs, rhs, u8::overflowing_sub)
-}
-
-#[cfg(all(test, feature = "std"))]
-mod tests {
-    use super::*;
-    use ink_prelude::vec::Vec;
-
-    #[test]
-    fn test_negate_bytes() {
-        fn negate_bytes_copy(bytes: &[u8]) -> Vec<u8> {
-            let mut buf = bytes.to_vec();
-            negate_bytes(&mut buf);
-            buf
-        }
-        fn test_for(bytes: &[u8], expected: &[u8]) {
-            assert_eq!(negate_bytes_copy(bytes), expected)
-        }
-        // Test for '0'
-        test_for(&[0x00], &[0x00]);
-        // Test for '1'
-        test_for(&[0x00, 0x01], &[0xFF, 0xFF]);
-        // Test for '-1' == '0xFF'
-        test_for(&[0xFF, 0xFF], &[0x00, 0x01]);
-        // Test for '42' == '0x2A'
-        //
-        // 0000 0000 0010 1010 | input
-        // 1111 1111 1101 0101 | flipped
-        // 1111 1111 1101 0110 | +1
-        //    F    F    D    6 | hex
-        test_for(&[0x00, 0x2A], &[0xFF, 0xD6]);
-    }
-
-    #[test]
-    fn test_slice_as_array() {
-        assert_eq!(slice4_as_array4::<i32>(&[]), None);
-        assert_eq!(slice4_as_array4(&[1, 2, 3, 4, 5]), None);
-        assert_eq!(slice4_as_array4(&[1, 2, 3, 4]), Some(&[1, 2, 3, 4]));
-        assert_eq!(slice4_as_array4(&[1, 2, 3]), None);
-    }
-
-    #[test]
-    fn test_bytes_add_bytes_eq() {
-        fn test_for(lhs: &[u8], rhs: &[u8], expected: &[u8]) {
-            fn bytes_add_bytes_copy(lhs: &[u8], rhs: &[u8]) -> Vec<u8> {
-                let mut lhs_vec = lhs.to_vec();
-                bytes_add_bytes(&mut lhs_vec, rhs);
-                lhs_vec
-            }
-            assert_eq!(bytes_add_bytes_copy(lhs, rhs).as_slice(), expected);
-            // Changing lhs with rhs should not change the result.
-            assert_eq!(bytes_add_bytes_copy(rhs, lhs).as_slice(), expected);
-        }
-        // 0 + 0 == 0
-        test_for(
-            &[0x00, 0x00, 0x00, 0x00],
-            &[0x00, 0x00, 0x00, 0x00],
-            &[0x00, 0x00, 0x00, 0x00],
-        );
-        // 0 + 0x42 == 0x42
-        test_for(
-            &[0x00, 0x00, 0x00, 0x00],
-            &[0x00, 0x00, 0x00, 0x42],
-            &[0x00, 0x00, 0x00, 0x42],
-        );
-        // u32::MAX + 1 == 0
-        test_for(
-            &[0xFF, 0xFF, 0xFF, 0xFF],
-            &[0x00, 0x00, 0x00, 0x01],
-            &[0x00, 0x00, 0x00, 0x00],
-        );
-        // 0 + u32::MAX == u32::MAX
-        test_for(
-            &[0x00, 0x00, 0x00, 0x00],
-            &[0xFF, 0xFF, 0xFF, 0xFF],
-            &[0xFF, 0xFF, 0xFF, 0xFF],
-        );
-        // 0x12345678 + 0x9ABCDEF0 = 0xACF13568
-        test_for(
-            &[0x12, 0x34, 0x56, 0x78],
-            &[0x9A, 0xBC, 0xDE, 0xF0],
-            &[0xAC, 0xF1, 0x35, 0x68],
-        );
-    }
-
-    #[test]
-    fn test_bytes_add_bytes() {
-        fn test_for(lhs: &[u8], rhs: &[u8], expected: &[u8]) {
-            fn bytes_add_bytes_copy(lhs: &[u8], rhs: &[u8]) -> Vec<u8> {
-                let mut lhs_vec = lhs.to_vec();
-                bytes_add_bytes(&mut lhs_vec, rhs);
-                lhs_vec
-            }
-            assert_eq!(bytes_add_bytes_copy(lhs, rhs).as_slice(), expected);
-        }
-        // 0 + 0 == 0
-        test_for(
-            &[0x00, 0x00, 0x00, 0x00],
-            &[0x00],
-            &[0x00, 0x00, 0x00, 0x00],
-        );
-        // 0 + 0x42 == 0x42
-        test_for(
-            &[0x00, 0x00, 0x00, 0x00],
-            &[0x42],
-            &[0x00, 0x00, 0x00, 0x42],
-        );
-        // 0xAB_CD_00_00 + 0x00_00_98_76 == 0xAB_CD_98_76
-        test_for(
-            &[0xAB, 0xCD, 0x00, 0x00],
-            &[0x98, 0x76],
-            &[0xAB, 0xCD, 0x98, 0x76],
-        );
-        // 0xFFFF + 0xFFFF == 0x0001_FFFE
-        test_for(
-            &[0x00, 0x00, 0xFF, 0xFF],
-            &[0xFF, 0xFF],
-            &[0x00, 0x01, 0xFF, 0xFE],
-        );
-    }
-}
diff --git a/primitives/src/key.rs b/primitives/src/key.rs
index 25e1fe36ff..8e087516db 100644
--- a/primitives/src/key.rs
+++ b/primitives/src/key.rs
@@ -1,4 +1,4 @@
-// Copyright 2018-2019 Parity Technologies (UK) Ltd.
+// Copyright 2018-2020 Parity Technologies (UK) Ltd.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -12,306 +12,384 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-use crate::byte_utils;
-use scale::{
-    Decode,
-    Encode,
+use core::{
+    fmt,
+    ops::{
+        Add,
+        AddAssign,
+    },
 };
 
-/// Typeless generic key into contract storage.
+/// Key into contract storage.
 ///
-/// Can be compared to a raw pointer featuring pointer arithmetic.
+/// Used to identify contract storage cells for read and write operations.
+/// Can be compared to a raw pointer and features simple pointer arithmetic.
 ///
 /// # Note
 ///
-/// This is the most low-level method to access contract storage.
+/// This is the most low-level primitive to identify contract storage cells.
 ///
 /// # Unsafe
 ///
-/// - Does not restrict ownership.
-/// - Can read and write to any storage location.
-/// - Does not synchronize between main memory and contract storage.
-/// - Violates Rust's mutability and immutability guarantees.
-///
-/// Prefer using types found in `collections` or `Synced` type.
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Encode, Decode)]
-#[cfg_attr(feature = "std", derive(scale_info::Metadata))]
-pub struct Key(pub [u8; 32]);
+/// Prefer using high-level types found in `ink_core` to operate on the contract
+/// storage.
+#[derive(Copy, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[repr(transparent)]
+pub struct Key([u64; 4]);
 
-impl From<[u8; 32]> for Key {
-    fn from(bytes: [u8; 32]) -> Self {
-        Self(bytes)
+impl Key {
+    fn write_bytes(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "0x")?;
+        for limb in &self.0 {
+            write!(f, "_")?;
+            for byte in &limb.to_le_bytes() {
+                write!(f, "{:02X}", byte)?;
+            }
+        }
+        Ok(())
     }
 }
 
-impl core::fmt::Debug for Key {
-    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
+impl fmt::Debug for Key {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "Key(")?;
-        <Self as core::fmt::Display>::fmt(self, f)?;
+        self.write_bytes(f)?;
         write!(f, ")")?;
         Ok(())
     }
 }
 
-impl core::fmt::Display for Key {
-    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
-        write!(f, "0x")?;
-        if f.alternate() {
-            let bytes = self.as_bytes();
-            write!(
-                f,
-                "{:02X}{:02X}_{:02X}{:02X}_……_{:02X}{:02X}_{:02X}{:02X}",
-                bytes[0],
-                bytes[1],
-                bytes[2],
-                bytes[3],
-                bytes[28],
-                bytes[29],
-                bytes[30],
-                bytes[31],
-            )?;
+impl fmt::Display for Key {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        self.write_bytes(f)
+    }
+}
+
+impl From<[u8; 32]> for Key {
+    #[inline]
+    fn from(bytes: [u8; 32]) -> Self {
+        if cfg!(target_endian = "little") {
+            // SAFETY: If the machine has little endian byte ordering we can
+            //         simply transmute the input bytes into the correct `u64`
+            //         byte ordering for the `Key` data structure. Otherwise
+            //         we have to manually convert them via the
+            //         `from_bytes_be_fallback` procedure.
+            //
+            // We decided to have the little endian as default format for Key
+            // instance since WebAssembly dictates little endian byte ordering
+            // for the execution environment.
+            Self(unsafe { ::core::mem::transmute::<[u8; 32], [u64; 4]>(bytes) })
         } else {
-            for (n, byte) in self.as_bytes().iter().enumerate() {
-                write!(f, "{:02X}", byte)?;
-                if n % 4 == 0 && n != 32 {
-                    write!(f, "_")?;
-                }
-            }
+            Self::from_bytes_be_fallback(bytes)
         }
-        Ok(())
     }
 }
 
 impl Key {
-    /// Returns the byte slice of this key.
-    pub fn as_bytes(&self) -> &[u8] {
-        &self.0
+    /// Creates a new key from the given bytes.
+    ///
+    /// # Note
+    ///
+    /// This is a fallback procedure in case the target machine does not have
+    /// little endian byte ordering.
+    #[inline]
+    fn from_bytes_be_fallback(bytes: [u8; 32]) -> Self {
+        #[inline]
+        fn carve_out_u64_bytes(bytes: &[u8; 32], offset: u8) -> [u8; 8] {
+            let o = (offset * 8) as usize;
+            [
+                bytes[o],
+                bytes[o + 1],
+                bytes[o + 2],
+                bytes[o + 3],
+                bytes[o + 4],
+                bytes[o + 5],
+                bytes[o + 6],
+                bytes[o + 7],
+            ]
+        }
+        Self([
+            u64::from_le_bytes(carve_out_u64_bytes(&bytes, 0)),
+            u64::from_le_bytes(carve_out_u64_bytes(&bytes, 1)),
+            u64::from_le_bytes(carve_out_u64_bytes(&bytes, 2)),
+            u64::from_le_bytes(carve_out_u64_bytes(&bytes, 3)),
+        ])
+    }
+
+    /// Tries to return the underlying bytes as slice.
+    ///
+    /// This only returns `Some` if the execution environment has little-endian
+    /// byte order.
+    pub fn try_as_bytes(&self) -> Option<&[u8; 32]> {
+        if cfg!(target_endian = "little") {
+            return Some(self.as_bytes())
+        }
+        None
     }
 
-    /// Returns the mutable byte slice of this key.
-    pub fn as_bytes_mut(&mut self) -> &mut [u8] {
-        &mut self.0
+    /// Returns the underlying bytes of the key.
+    ///
+    /// This only works and is supported if the target machine has little-endian
+    /// byte ordering. Use [`try_as_bytes`] as a general procedure instead.
+    #[cfg(target_endian = "little")]
+    pub fn as_bytes(&self) -> &[u8; 32] {
+        // SAFETY: This pointer cast is possible since the outer struct
+        //         (Key) is `repr(transparent)` and since we restrict
+        //         ourselves to little-endian byte ordering. In any other
+        //         case this is invalid which is why return `None` as
+        //         fallback.
+        unsafe { &*(&self.0 as *const [u64; 4] as *const [u8; 32]) }
     }
 }
 
-impl core::ops::Sub for Key {
-    type Output = KeyDiff;
+impl scale::Encode for Key {
+    #[inline(always)]
+    fn size_hint(&self) -> usize {
+        32
+    }
 
-    fn sub(self, rhs: Self) -> KeyDiff {
-        let mut lhs = self;
-        let mut rhs = rhs;
-        byte_utils::negate_bytes(rhs.as_bytes_mut());
-        byte_utils::bytes_add_bytes(lhs.as_bytes_mut(), rhs.as_bytes());
-        KeyDiff(lhs.0)
+    #[inline]
+    fn encode_to<T: scale::Output>(&self, dest: &mut T) {
+        if cfg!(target_endian = "little") {
+            dest.write(self.try_as_bytes().expect("little endian is asserted"))
+        } else {
+            dest.write(&self.to_bytes())
+        }
     }
 }
 
-/// The difference between two keys.
-///
-/// This is the result of substracting one key from another.
-#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub struct KeyDiff([u8; 32]);
-
-macro_rules! impl_try_to_prim {
-	(
-		$( #[$attr:meta] )*
-		$name:ident, $prim:ty, $conv:ident
-	) => {
-		impl KeyDiff {
-			$( #[$attr] )*
-			pub fn $name(&self) -> Option<$prim> {
-				const KEY_BYTES: usize = 32;
-				const PRIM_BYTES: usize = core::mem::size_of::<$prim>();
-				if self.as_bytes().iter().take(KEY_BYTES - PRIM_BYTES).any(|&byte| byte != 0x0) {
-					return None
-				}
-				let value = <$prim>::from_be_bytes(
-					*byte_utils::$conv(&self.as_bytes()[(KEY_BYTES - PRIM_BYTES)..KEY_BYTES])
-						.unwrap()
-				);
-				Some(value)
-			}
-		}
-	};
+impl scale::Decode for Key {
+    #[inline]
+    fn decode<I: scale::Input>(input: &mut I) -> Result<Self, scale::Error> {
+        Ok(Self::from(<[u8; 32] as scale::Decode>::decode(input)?))
+    }
 }
 
-impl_try_to_prim!(
-    /// Tries to convert the key difference to a `u32` if possible.
-    ///
-    /// Returns `None` if the resulting value is out of bounds.
-    try_to_u32,
-    u32,
-    slice4_as_array4
-);
-impl_try_to_prim!(
-    /// Tries to convert the key difference to a `u64` if possible.
-    ///
-    /// Returns `None` if the resulting value is out of bounds.
-    try_to_u64,
-    u64,
-    slice8_as_array8
-);
-impl_try_to_prim!(
-    /// Tries to convert the key difference to a `u128` if possible.
-    ///
-    /// Returns `None` if the resulting value is out of bounds.
-    try_to_u128,
-    u128,
-    slice16_as_array16
-);
-
-impl KeyDiff {
-    /// Returns the byte slice of this key difference.
-    fn as_bytes(&self) -> &[u8] {
-        &self.0
+#[cfg(target_endian = "little")]
+impl Key {
+    /// Returns the bytes that are representing the key.
+    #[inline]
+    pub fn to_bytes(&self) -> [u8; 32] {
+        if cfg!(target_endian = "little") {
+            // SAFETY: This pointer cast is possible since the outer struct
+            //         (Key) is `repr(transparent)` and since we restrict
+            //         ourselves to little-endian byte ordering. In any other
+            //         case this is invalid which is why return `None` as
+            //         fallback.
+            unsafe { core::mem::transmute::<[u64; 4], [u8; 32]>(self.0) }
+        } else {
+            self.to_bytes_be_fallback()
+        }
+    }
+
+    /// Fallback big-endian procedure to return the underlying bytes of `self`.
+    fn to_bytes_be_fallback(&self) -> [u8; 32] {
+        let mut result = [0x00; 32];
+        for i in 0..4 {
+            let o = i * 8;
+            result[o..(o + 8)].copy_from_slice(&self.0[i].to_le_bytes());
+        }
+        result
     }
 }
 
-macro_rules! impl_add_sub_for_key {
-    ( $prim:ty ) => {
-        impl core::ops::Add<$prim> for Key {
-            type Output = Self;
+impl Add<u64> for Key {
+    type Output = Key;
 
-            fn add(self, rhs: $prim) -> Self::Output {
-                let mut result = self;
-                result += rhs;
-                result
-            }
-        }
+    fn add(mut self, rhs: u64) -> Self::Output {
+        self += rhs;
+        self
+    }
+}
 
-        impl core::ops::AddAssign<$prim> for Key {
-            fn add_assign(&mut self, rhs: $prim) {
-                byte_utils::bytes_add_bytes(self.as_bytes_mut(), &(rhs.to_be_bytes()));
-            }
-        }
+impl<'a> Add<u64> for &'a Key {
+    type Output = Key;
 
-        impl core::ops::Sub<$prim> for Key {
-            type Output = Self;
+    fn add(self, rhs: u64) -> Self::Output {
+        <Key as Add<u64>>::add(*self, rhs)
+    }
+}
 
-            fn sub(self, rhs: $prim) -> Self::Output {
-                let mut result = self;
-                result -= rhs;
-                result
-            }
-        }
+impl<'a> Add<&'a u64> for Key {
+    type Output = Key;
 
-        impl core::ops::SubAssign<$prim> for Key {
-            fn sub_assign(&mut self, rhs: $prim) {
-                byte_utils::bytes_sub_bytes(self.as_bytes_mut(), &rhs.to_be_bytes());
-            }
-        }
-    };
+    fn add(self, rhs: &'a u64) -> Self::Output {
+        <Key as Add<u64>>::add(self, *rhs)
+    }
 }
 
-impl_add_sub_for_key!(u32);
-impl_add_sub_for_key!(u64);
-impl_add_sub_for_key!(u128);
+impl<'a, 'b> Add<&'b u64> for &'a Key {
+    type Output = Key;
+
+    fn add(self, rhs: &'b u64) -> Self::Output {
+        <&'a Key as Add<u64>>::add(self, *rhs)
+    }
+}
+
+#[cfg(feature = "std")]
+const _: () = {
+    use scale_info::{
+        build::Fields,
+        Path,
+        Type,
+        TypeInfo,
+    };
+
+    impl TypeInfo for Key {
+        fn type_info() -> Type {
+            Type::builder()
+                .path(Path::new("Key", "ink_primitives"))
+                .composite(Fields::unnamed().field_of::<[u8; 32]>())
+        }
+    }
+};
+
+impl AddAssign<u64> for Key {
+    #[inline]
+    #[rustfmt::skip]
+    fn add_assign(&mut self, rhs: u64) {
+        let (res_0,  ovfl_0) = self.0[0].overflowing_add(rhs);
+        let (res_1,  ovfl_1) = self.0[1].overflowing_add(ovfl_0 as u64);
+        let (res_2,  ovfl_2) = self.0[2].overflowing_add(ovfl_1 as u64);
+        let (res_3, _ovfl_3) = self.0[3].overflowing_add(ovfl_2 as u64);
+        self.0[0] = res_0;
+        self.0[1] = res_1;
+        self.0[2] = res_2;
+        self.0[3] = res_3;
+    }
+}
 
 #[cfg(test)]
 mod tests {
     use super::*;
 
+    fn test_bytes() -> [u8; 32] {
+        *b"\
+            \x00\x01\x02\x03\x04\x05\x06\x07\
+            \x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\
+            \x10\x11\x12\x13\x14\x15\x16\x17\
+            \x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\
+        "
+    }
+
+    #[test]
+    fn default_works() {
+        assert_eq!(<Key as Default>::default().to_bytes(), [0x00; 32]);
+    }
+
     #[test]
-    fn key_sub() {
-        assert_eq!(Key([0x42; 32]), Key([0x42; 32]));
-        assert_eq!(Key([0x00; 32]) - 1_u32, Key([0xFF; 32]));
+    fn debug_works() {
+        let key = Key::from(test_bytes());
         assert_eq!(
-            Key([0x01; 32]) - 1_u32,
-            Key([
-                0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-                0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-                0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00
-            ])
+            format!("{:?}", key),
+            String::from(
+                "Key(0x\
+                    _0001020304050607\
+                    _08090A0B0C0D0E0F\
+                    _1011121314151617\
+                    _18191A1B1C1D1E1F\
+                )"
+            ),
         );
-        {
-            let key_u32_max_value = Key([
-                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
-            ]);
-            assert_eq!(key_u32_max_value - u32::max_value(), Key([0x00; 32]));
-        }
-        {
-            let key_a = Key([
-                0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x10, 0x20, 0x30, 0x40,
-                0x50, 0x60, 0x70, 0x80, 0xA0, 0xB1, 0xC2, 0xD3, 0xE4, 0xF5, 0x06, 0x17,
-                0x00, 0x22, 0x44, 0x66, 0x88, 0xAA, 0xCC, 0xEE,
-            ]);
-            let b: u32 = 0xFA09_51C3;
-            let expected_b = Key([
-                0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x10, 0x20, 0x30, 0x40,
-                0x50, 0x60, 0x70, 0x80, 0xA0, 0xB1, 0xC2, 0xD3, 0xE4, 0xF5, 0x06, 0x17,
-                0x00, 0x22, 0x44, 0x65, 0x8E, 0xA1, 0x7B, 0x2B,
-            ]);
-            assert_eq!(key_a - b, expected_b);
-            let c: u64 = 0xFBDC_BEEF_9999_1234;
-            let expected_c = Key([
-                0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x10, 0x20, 0x30, 0x40,
-                0x50, 0x60, 0x70, 0x80, 0xA0, 0xB1, 0xC2, 0xD3, 0xE4, 0xF5, 0x06, 0x16,
-                0x04, 0x45, 0x85, 0x76, 0xEF, 0x11, 0xBA, 0xBA,
-            ]);
-            assert_eq!(key_a - c, expected_c);
-        }
     }
 
     #[test]
-    fn as_bytes() {
-        let mut key = Key([0x42; 32]);
-        assert_eq!(key.as_bytes(), &[0x42; 32]);
-        assert_eq!(key.as_bytes_mut(), &mut [0x42; 32]);
+    #[rustfmt::skip]
+    fn from_works() {
+        let test_bytes = test_bytes();
+        assert_eq!(Key::from(test_bytes).to_bytes(), test_bytes);
+        assert_eq!(Key::from_bytes_be_fallback(test_bytes).to_bytes(), test_bytes);
+        assert_eq!(Key::from(test_bytes).to_bytes_be_fallback(), test_bytes);
+        assert_eq!(Key::from_bytes_be_fallback(test_bytes).to_bytes_be_fallback(), test_bytes);
     }
 
     #[test]
-    fn key_diff() {
-        let key1 = Key([0x0; 32]);
-        let key2 = key1 + 0x42_u32;
-        let key3 = key1 + u32::max_value() + 1_u32;
-        let key4 = key1 + u64::max_value();
-        assert_eq!(
-            key2 - key1,
-            KeyDiff([
-                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42,
-            ])
-        );
-        assert_eq!((key2 - key1).try_to_u32(), Some(0x42));
-        assert_eq!((key2 - key1).try_to_u64(), Some(0x42));
-        assert_eq!(
-            key3 - key1,
-            KeyDiff([
-                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
-            ])
-        );
-        assert_eq!((key3 - key1).try_to_u32(), None);
-        assert_eq!(
-            (key3 - key1).try_to_u64(),
-            Some(u32::max_value() as u64 + 1)
-        );
-        assert_eq!(
-            key4 - key1,
-            KeyDiff([
-                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-            ])
-        );
-        assert_eq!((key4 - key1).try_to_u32(), None);
-        assert_eq!((key4 - key1).try_to_u64(), Some(u64::max_value()));
-        assert_eq!(
-            key4 - key3,
-            KeyDiff([
-                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,
-            ])
-        );
-        assert_eq!((key4 - key1).try_to_u32(), None);
-        assert_eq!(
-            (key4 - key3).try_to_u64(),
-            Some(u64::max_value() - (u32::max_value() as u64 + 1))
-        );
+    fn add_one_to_zero() {
+        let bytes = [0x00; 32];
+        let expected = {
+            let mut bytes = [0x00; 32];
+            bytes[0] = 0x01;
+            bytes
+        };
+        let mut key = Key::from(bytes);
+        key.add_assign(1u64);
+        assert_eq!(key.to_bytes(), expected);
+    }
+
+    #[test]
+    fn add_with_ovfl() {
+        let bytes = *b"\
+            \xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\
+            \x00\x00\x00\x00\x00\x00\x00\x00\
+            \x00\x00\x00\x00\x00\x00\x00\x00\
+            \x00\x00\x00\x00\x00\x00\x00\x00\
+        ";
+        let expected = {
+            let mut expected = [0x00; 32];
+            expected[8] = 0x01;
+            expected
+        };
+        let mut key = Key::from(bytes);
+        key.add_assign(1u64);
+        assert_eq!(key.to_bytes(), expected);
+    }
+
+    #[test]
+    fn add_with_ovfl_2() {
+        let bytes = *b"\
+            \xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\
+            \xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\
+            \x00\x00\x00\x00\x00\x00\x00\x00\
+            \x00\x00\x00\x00\x00\x00\x00\x00\
+        ";
+        let expected = {
+            let mut expected = [0x00; 32];
+            expected[16] = 0x01;
+            expected
+        };
+        let mut key = Key::from(bytes);
+        key.add_assign(1u64);
+        assert_eq!(key.to_bytes(), expected);
+    }
+
+    #[test]
+    fn add_with_ovfl_3() {
+        let bytes = *b"\
+            \xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\
+            \xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\
+            \xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\
+            \x00\x00\x00\x00\x00\x00\x00\x00\
+        ";
+        let expected = {
+            let mut expected = [0x00; 32];
+            expected[24] = 0x01;
+            expected
+        };
+        let mut key = Key::from(bytes);
+        key.add_assign(1u64);
+        assert_eq!(key.to_bytes(), expected);
+    }
+
+    #[test]
+    fn add_with_wrap() {
+        let bytes = [0xFF; 32];
+        let expected = [0x00; 32];
+        let mut key = Key::from(bytes);
+        key.add_assign(1u64);
+        assert_eq!(key.to_bytes(), expected);
+    }
+
+    #[test]
+    fn add_assign_to_zero() {
+        for test_value in &[0_u64, 1, 42, 10_000, u32::MAX as u64, u64::MAX] {
+            let mut key = <Key as Default>::default();
+            let expected = {
+                let mut expected = [0x00; 32];
+                expected[0..8].copy_from_slice(&test_value.to_le_bytes());
+                expected
+            };
+            key.add_assign(*test_value);
+            assert_eq!(key.to_bytes(), expected);
+        }
     }
 }
diff --git a/primitives/src/key2.rs b/primitives/src/key2.rs
deleted file mode 100644
index c0efed64b2..0000000000
--- a/primitives/src/key2.rs
+++ /dev/null
@@ -1,311 +0,0 @@
-// Copyright 2018-2020 Parity Technologies (UK) Ltd.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-use core::{
-    fmt,
-    ops::AddAssign,
-};
-
-/// Key into contract storage.
-///
-/// Used to identify contract storage cells for read and write operations.
-/// Can be compared to a raw pointer and features simple pointer arithmetic.
-///
-/// # Note
-///
-/// This is the most low-level primitive to identify contract storage cells.
-///
-/// # Unsafe
-///
-/// Prefer using high-level types found in `ink_core` to operate on the contract
-/// storage.
-#[derive(Copy, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-#[repr(transparent)]
-pub struct Key([u64; 4]);
-
-impl Key {
-    fn write_bytes(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "0x")?;
-        for limb in &self.0 {
-            write!(f, "_")?;
-            for byte in &limb.to_le_bytes() {
-                write!(f, "{:02X}", byte)?;
-            }
-        }
-        Ok(())
-    }
-}
-
-impl fmt::Debug for Key {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "Key(")?;
-        self.write_bytes(f)?;
-        write!(f, ")")?;
-        Ok(())
-    }
-}
-
-impl fmt::Display for Key {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        self.write_bytes(f)
-    }
-}
-
-impl From<[u8; 32]> for Key {
-    #[inline]
-    fn from(bytes: [u8; 32]) -> Self {
-        if cfg!(target_endian = "little") {
-            // SAFETY: If the machine has little endian byte ordering we can
-            //         simply transmute the input bytes into the correct `u64`
-            //         byte ordering for the `Key` data structure. Otherwise
-            //         we have to manually convert them via the
-            //         `from_bytes_be_fallback` procedure.
-            //
-            // We decided to have the little endian as default format for Key
-            // instance since WebAssembly dictates little endian byte ordering
-            // for the execution environment.
-            Self(unsafe { ::core::mem::transmute::<[u8; 32], [u64; 4]>(bytes) })
-        } else {
-            Self::from_bytes_be_fallback(bytes)
-        }
-    }
-}
-
-impl Key {
-    /// Creates a new key from the given bytes.
-    ///
-    /// # Note
-    ///
-    /// This is a fallback procedure in case the target machine does not have
-    /// little endian byte ordering.
-    #[inline]
-    fn from_bytes_be_fallback(bytes: [u8; 32]) -> Self {
-        #[inline]
-        fn carve_out_u64_bytes(bytes: &[u8; 32], offset: u8) -> [u8; 8] {
-            let o = (offset * 8) as usize;
-            [
-                bytes[o],
-                bytes[o + 1],
-                bytes[o + 2],
-                bytes[o + 3],
-                bytes[o + 4],
-                bytes[o + 5],
-                bytes[o + 6],
-                bytes[o + 7],
-            ]
-        }
-        Self([
-            u64::from_le_bytes(carve_out_u64_bytes(&bytes, 0)),
-            u64::from_le_bytes(carve_out_u64_bytes(&bytes, 1)),
-            u64::from_le_bytes(carve_out_u64_bytes(&bytes, 2)),
-            u64::from_le_bytes(carve_out_u64_bytes(&bytes, 3)),
-        ])
-    }
-
-    /// Tries to return the underlying bytes as slice.
-    ///
-    /// This only returns `Some` if the execution environment has little-endian
-    /// byte order.
-    pub fn try_as_bytes(&self) -> Option<&[u8; 32]> {
-        if cfg!(target_endian = "little") {
-            return Some(
-                // SAFETY: This pointer cast is possible since the outer struct
-                //         (Key) is `repr(transparent)` and since we restrict
-                //         ourselves to little-endian byte ordering. In any other
-                //         case this is invalid which is why return `None` as
-                //         fallback.
-                unsafe { &*(&self.0 as *const [u64; 4] as *const [u8; 32]) },
-            )
-        }
-        None
-    }
-}
-
-#[cfg(target_endian = "little")]
-impl Key {
-    /// Returns the bytes that are representing the key.
-    #[inline]
-    pub fn to_bytes(&self) -> [u8; 32] {
-        if cfg!(target_endian = "little") {
-            // SAFETY: This pointer cast is possible since the outer struct
-            //         (Key) is `repr(transparent)` and since we restrict
-            //         ourselves to little-endian byte ordering. In any other
-            //         case this is invalid which is why return `None` as
-            //         fallback.
-            unsafe { core::mem::transmute::<[u64; 4], [u8; 32]>(self.0) }
-        } else {
-            self.to_bytes_be_fallback()
-        }
-    }
-
-    /// Fallback big-endian procedure to return the underlying bytes of `self`.
-    fn to_bytes_be_fallback(&self) -> [u8; 32] {
-        let mut result = [0x00; 32];
-        for i in 0..4 {
-            let o = i * 8;
-            result[o..(o + 8)].copy_from_slice(&self.0[i].to_le_bytes());
-        }
-        result
-    }
-}
-
-impl AddAssign<u64> for Key {
-    #[inline]
-    #[rustfmt::skip]
-    fn add_assign(&mut self, rhs: u64) {
-        let (res_0,  ovfl_0) = self.0[0].overflowing_add(rhs);
-        let (res_1,  ovfl_1) = self.0[1].overflowing_add(ovfl_0 as u64);
-        let (res_2,  ovfl_2) = self.0[2].overflowing_add(ovfl_1 as u64);
-        let (res_3, _ovfl_3) = self.0[3].overflowing_add(ovfl_2 as u64);
-        self.0[0] = res_0;
-        self.0[1] = res_1;
-        self.0[2] = res_2;
-        self.0[3] = res_3;
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    fn test_bytes() -> [u8; 32] {
-        *b"\
-            \x00\x01\x02\x03\x04\x05\x06\x07\
-            \x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\
-            \x10\x11\x12\x13\x14\x15\x16\x17\
-            \x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\
-        "
-    }
-
-    #[test]
-    fn default_works() {
-        assert_eq!(<Key as Default>::default().to_bytes(), [0x00; 32]);
-    }
-
-    #[test]
-    fn debug_works() {
-        let key = Key::from(test_bytes());
-        assert_eq!(
-            format!("{:?}", key),
-            String::from(
-                "Key(0x\
-                    _0001020304050607\
-                    _08090A0B0C0D0E0F\
-                    _1011121314151617\
-                    _18191A1B1C1D1E1F\
-                )"
-            ),
-        );
-    }
-
-    #[test]
-    #[rustfmt::skip]
-    fn from_works() {
-        let test_bytes = test_bytes();
-        assert_eq!(Key::from(test_bytes).to_bytes(), test_bytes);
-        assert_eq!(Key::from_bytes_be_fallback(test_bytes).to_bytes(), test_bytes);
-        assert_eq!(Key::from(test_bytes).to_bytes_be_fallback(), test_bytes);
-        assert_eq!(Key::from_bytes_be_fallback(test_bytes).to_bytes_be_fallback(), test_bytes);
-    }
-
-    #[test]
-    fn add_one_to_zero() {
-        let bytes = [0x00; 32];
-        let expected = {
-            let mut bytes = [0x00; 32];
-            bytes[0] = 0x01;
-            bytes
-        };
-        let mut key = Key::from(bytes);
-        key.add_assign(1u64);
-        assert_eq!(key.to_bytes(), expected);
-    }
-
-    #[test]
-    fn add_with_ovfl() {
-        let bytes = *b"\
-            \xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\
-            \x00\x00\x00\x00\x00\x00\x00\x00\
-            \x00\x00\x00\x00\x00\x00\x00\x00\
-            \x00\x00\x00\x00\x00\x00\x00\x00\
-        ";
-        let expected = {
-            let mut expected = [0x00; 32];
-            expected[8] = 0x01;
-            expected
-        };
-        let mut key = Key::from(bytes);
-        key.add_assign(1u64);
-        assert_eq!(key.to_bytes(), expected);
-    }
-
-    #[test]
-    fn add_with_ovfl_2() {
-        let bytes = *b"\
-            \xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\
-            \xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\
-            \x00\x00\x00\x00\x00\x00\x00\x00\
-            \x00\x00\x00\x00\x00\x00\x00\x00\
-        ";
-        let expected = {
-            let mut expected = [0x00; 32];
-            expected[16] = 0x01;
-            expected
-        };
-        let mut key = Key::from(bytes);
-        key.add_assign(1u64);
-        assert_eq!(key.to_bytes(), expected);
-    }
-
-    #[test]
-    fn add_with_ovfl_3() {
-        let bytes = *b"\
-            \xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\
-            \xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\
-            \xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\
-            \x00\x00\x00\x00\x00\x00\x00\x00\
-        ";
-        let expected = {
-            let mut expected = [0x00; 32];
-            expected[24] = 0x01;
-            expected
-        };
-        let mut key = Key::from(bytes);
-        key.add_assign(1u64);
-        assert_eq!(key.to_bytes(), expected);
-    }
-
-    #[test]
-    fn add_with_wrap() {
-        let bytes = [0xFF; 32];
-        let expected = [0x00; 32];
-        let mut key = Key::from(bytes);
-        key.add_assign(1u64);
-        assert_eq!(key.to_bytes(), expected);
-    }
-
-    #[test]
-    fn add_assign_to_zero() {
-        for test_value in &[0_u64, 1, 42, 10_000, u32::MAX as u64, u64::MAX] {
-            let mut key = <Key as Default>::default();
-            let expected = {
-                let mut expected = [0x00; 32];
-                expected[0..8].copy_from_slice(&test_value.to_le_bytes());
-                expected
-            };
-            key.add_assign(*test_value);
-            assert_eq!(key.to_bytes(), expected);
-        }
-    }
-}
diff --git a/primitives/src/key_ptr.rs b/primitives/src/key_ptr.rs
index 3a99356394..f6ab284140 100644
--- a/primitives/src/key_ptr.rs
+++ b/primitives/src/key_ptr.rs
@@ -21,22 +21,24 @@ use crate::Key;
 #[derive(Debug, Copy, Clone)]
 pub struct KeyPtr {
     /// The underlying offset key.
-    offset: Key,
+    key: Key,
+    /// The last shift performed.
+    last_shift: u64,
 }
 
 impl From<Key> for KeyPtr {
     #[inline]
     fn from(key: Key) -> Self {
-        Self { offset: key }
+        Self { key, last_shift: 0 }
     }
 }
 
 impl KeyPtr {
     /// Advances the key pointer by the given amount and returns the old value.
     #[inline]
-    pub fn advance_by(&mut self, amount: u64) -> Key {
-        let copy = self.offset;
-        self.offset += amount;
-        copy
+    pub fn advance_by(&mut self, new_shift: u64) -> &Key {
+        let old_shift = core::mem::replace(&mut self.last_shift, new_shift);
+        self.key += old_shift;
+        &self.key
     }
 }
diff --git a/primitives/src/key_ptr2.rs b/primitives/src/key_ptr2.rs
deleted file mode 100644
index c465d7d65e..0000000000
--- a/primitives/src/key_ptr2.rs
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2019-2020 Parity Technologies (UK) Ltd.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-use crate::Key2 as Key;
-
-/// A key pointer.
-///
-/// This wraps a base key and provides an interface to mimic pointer arithmetics.
-/// Mainly used to coordinate keys through static storage structures.
-#[derive(Debug, Copy, Clone)]
-pub struct KeyPtr {
-    /// The underlying offset key.
-    key: Key,
-    /// The last shift performed.
-    last_shift: u64,
-}
-
-impl From<Key> for KeyPtr {
-    #[inline]
-    fn from(key: Key) -> Self {
-        Self { key, last_shift: 0 }
-    }
-}
-
-impl KeyPtr {
-    /// Advances the key pointer by the given amount and returns the old value.
-    #[inline]
-    pub fn advance_by(&mut self, new_shift: u64) -> &Key {
-        let old_shift = core::mem::replace(&mut self.last_shift, new_shift);
-        self.key += old_shift;
-        &self.key
-    }
-}
diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs
index 5809d6de8b..5a21ec310c 100644
--- a/primitives/src/lib.rs
+++ b/primitives/src/lib.rs
@@ -23,18 +23,10 @@
 
 #![cfg_attr(not(feature = "std"), no_std)]
 
-mod byte_utils;
 mod key;
-mod key2;
 mod key_ptr;
-mod key_ptr2;
 
 pub use self::{
-    key::{
-        Key,
-        KeyDiff,
-    },
-    key2::Key as Key2,
+    key::Key,
     key_ptr::KeyPtr,
-    key_ptr2::KeyPtr as KeyPtr2,
 };


Test patch:
diff --git a/abi/src/layout2/tests.rs b/abi/src/layout2/tests.rs
index 7353903931..de6b4e2fec 100644
--- a/abi/src/layout2/tests.rs
+++ b/abi/src/layout2/tests.rs
@@ -17,7 +17,7 @@ use ink_primitives::KeyPtr;
 
 #[test]
 fn layout_key_works() {
-    let layout_key = LayoutKey::from(Key([0x01; 32]));
+    let layout_key = LayoutKey::from(Key::from([0x01; 32]));
     let json = serde_json::to_string(&layout_key).unwrap();
     assert_eq!(
         json,
@@ -41,7 +41,7 @@ fn named_fields_struct_layout(key_ptr: &mut KeyPtr) -> Layout {
 
 #[test]
 fn named_fields_work() {
-    let layout = named_fields_struct_layout(&mut KeyPtr::from(Key([0x00; 32])));
+    let layout = named_fields_struct_layout(&mut KeyPtr::from(Key::from([0x00; 32])));
     let mut registry = Registry::new();
     let compacted = layout.into_compact(&mut registry);
     let json = serde_json::to_value(&compacted).unwrap();
@@ -66,10 +66,10 @@ fn named_fields_work() {
                         "layout": {
                             "Cell": {
                                 "key": "0x\
+                                    0100000000000000\
                                     0000000000000000\
                                     0000000000000000\
-                                    0000000000000000\
-                                    0000000000000001",
+                                    0000000000000000",
                                 "ty": 2,
                             }
                         },
@@ -98,7 +98,7 @@ fn tuple_struct_layout(key_ptr: &mut KeyPtr) -> Layout {
 
 #[test]
 fn tuple_struct_work() {
-    let layout = tuple_struct_layout(&mut KeyPtr::from(Key([0x00; 32])));
+    let layout = tuple_struct_layout(&mut KeyPtr::from(Key::from([0x00; 32])));
     let mut registry = Registry::new();
     let compacted = layout.into_compact(&mut registry);
     let json = serde_json::to_value(&compacted).unwrap();
@@ -123,10 +123,10 @@ fn tuple_struct_work() {
                         "layout": {
                             "Cell": {
                                 "key": "0x\
+                                    0100000000000000\
                                     0000000000000000\
                                     0000000000000000\
-                                    0000000000000000\
-                                    0000000000000001",
+                                    0000000000000000",
                                 "ty": 2,
                             }
                         },
@@ -153,7 +153,7 @@ fn clike_enum_layout(key_ptr: &mut KeyPtr) -> Layout {
 
 #[test]
 fn clike_enum_work() {
-    let layout = clike_enum_layout(&mut KeyPtr::from(Key([0x00; 32])));
+    let layout = clike_enum_layout(&mut KeyPtr::from(Key::from([0x00; 32])));
     let mut registry = Registry::new();
     let compacted = layout.into_compact(&mut registry);
     let json = serde_json::to_value(&compacted).unwrap();
@@ -184,7 +184,7 @@ fn clike_enum_work() {
 
 fn mixed_enum_layout(key_ptr: &mut KeyPtr) -> Layout {
     EnumLayout::new(
-        key_ptr.advance_by(1),
+        *key_ptr.advance_by(1),
         vec![
             (Discriminant(0), StructLayout::new(vec![])),
             {
@@ -234,7 +234,7 @@ fn mixed_enum_layout(key_ptr: &mut KeyPtr) -> Layout {
 
 #[test]
 fn mixed_enum_work() {
-    let layout = mixed_enum_layout(&mut KeyPtr::from(Key([0x00; 32])));
+    let layout = mixed_enum_layout(&mut KeyPtr::from(Key::from([0x00; 32])));
     let mut registry = Registry::new();
     let compacted = layout.into_compact(&mut registry);
     let json = serde_json::to_value(&compacted).unwrap();
@@ -256,10 +256,10 @@ fn mixed_enum_work() {
                                 "layout": {
                                     "Cell": {
                                         "key": "0x\
+                                            0100000000000000\
                                             0000000000000000\
                                             0000000000000000\
-                                            0000000000000000\
-                                            0000000000000001",
+                                            0000000000000000",
                                         "ty": 1,
                                     }
                                 },
@@ -269,10 +269,10 @@ fn mixed_enum_work() {
                                 "layout": {
                                     "Cell": {
                                         "key": "0x\
+                                            0200000000000000\
                                             0000000000000000\
                                             0000000000000000\
-                                            0000000000000000\
-                                            0000000000000002",
+                                            0000000000000000",
                                         "ty": 2,
                                     }
                                 },
@@ -286,10 +286,10 @@ fn mixed_enum_work() {
                                 "layout": {
                                     "Cell": {
                                         "key": "0x\
+                                            0100000000000000\
                                             0000000000000000\
                                             0000000000000000\
-                                            0000000000000000\
-                                            0000000000000001",
+                                            0000000000000000",
                                         "ty": 1,
                                     }
                                 },
@@ -299,10 +299,10 @@ fn mixed_enum_work() {
                                 "layout": {
                                     "Cell": {
                                         "key": "0x\
+                                            0200000000000000\
                                             0000000000000000\
                                             0000000000000000\
-                                            0000000000000000\
-                                            0000000000000002",
+                                            0000000000000000",
                                         "ty": 2,
                                     }
                                 },
@@ -333,7 +333,7 @@ fn unbounded_hashing_layout(key_ptr: &mut KeyPtr) -> Layout {
 
 #[test]
 fn unbounded_layout_works() {
-    let layout = unbounded_hashing_layout(&mut KeyPtr::from(Key([0x00; 32])));
+    let layout = unbounded_hashing_layout(&mut KeyPtr::from(Key::from([0x00; 32])));
     let mut registry = Registry::new();
     let compacted = layout.into_compact(&mut registry);
     let json = serde_json::to_value(&compacted).unwrap();
diff --git a/core/src/env/engine/off_chain/tests.rs b/core/src/env/engine/off_chain/tests.rs
index ce3e5fb547..48b2c39d50 100644
--- a/core/src/env/engine/off_chain/tests.rs
+++ b/core/src/env/engine/off_chain/tests.rs
@@ -21,15 +21,15 @@ use ink_primitives::Key;
 #[test]
 fn store_load_clear() -> Result<()> {
     env::test::run_test::<env::DefaultEnvTypes, _>(|_| {
-        let key = Key([0x42; 32]);
-        assert_eq!(env::get_contract_storage::<()>(key), None,);
-        env::set_contract_storage(key, &[0x05_u8; 5]);
+        let key = Key::from([0x42; 32]);
+        assert_eq!(env::get_contract_storage::<()>(&key), None,);
+        env::set_contract_storage(&key, &[0x05_u8; 5]);
         assert_eq!(
-            env::get_contract_storage::<[i8; 5]>(key),
+            env::get_contract_storage::<[i8; 5]>(&key),
             Some(Ok([0x05; 5])),
         );
-        env::clear_contract_storage(key);
-        assert_eq!(env::get_contract_storage::<[u8; 5]>(key), None,);
+        env::clear_contract_storage(&key);
+        assert_eq!(env::get_contract_storage::<[u8; 5]>(&key), None,);
         Ok(())
     })
 }
@@ -37,14 +37,14 @@ fn store_load_clear() -> Result<()> {
 #[test]
 fn key_add() -> Result<()> {
     env::test::run_test::<env::DefaultEnvTypes, _>(|_| {
-        let key00 = Key([0x0; 32]);
-        let key05 = key00 + 05_u32; // -> 5
-        let key10 = key00 + 10_u32; // -> 10         | same as key55
-        let key55 = key05 + 05_u32; // -> 5 + 5 = 10 | same as key10
-        env::set_contract_storage(key55, &42);
-        assert_eq!(env::get_contract_storage::<i32>(key10), Some(Ok(42)));
-        env::set_contract_storage(key10, &1337);
-        assert_eq!(env::get_contract_storage::<i32>(key55), Some(Ok(1337)));
+        let key00 = Key::from([0x0; 32]);
+        let key05 = key00 + 05_u64; // -> 5
+        let key10 = key00 + 10_u64; // -> 10         | same as key55
+        let key55 = key05 + 05_u64; // -> 5 + 5 = 10 | same as key10
+        env::set_contract_storage(&key55, &42);
+        assert_eq!(env::get_contract_storage::<i32>(&key10), Some(Ok(42)));
+        env::set_contract_storage(&key10, &1337);
+        assert_eq!(env::get_contract_storage::<i32>(&key55), Some(Ok(1337)));
         Ok(())
     })
 }
@@ -52,19 +52,19 @@ fn key_add() -> Result<()> {
 #[test]
 fn key_add_sub() -> Result<()> {
     env::test::run_test::<env::DefaultEnvTypes, _>(|_| {
-        let key0a = Key([0x0; 32]);
-        let key1a = key0a + 1337_u32;
-        let key2a = key0a + 42_u32;
-        let key3a = key0a + 52_u32;
-        let key2b = key3a - 10_u32;
-        let key1b = key2b - 42_u32;
-        let key0b = key1b + 2000_u32 - 663_u32; // same as key1a
-        env::set_contract_storage(key0a, &1);
-        env::set_contract_storage(key1a, &2);
-        env::set_contract_storage(key2a, &3);
-        assert_eq!(env::get_contract_storage::<i32>(key2b), Some(Ok(3)));
-        assert_eq!(env::get_contract_storage::<i32>(key1b), Some(Ok(1)));
-        assert_eq!(env::get_contract_storage::<i32>(key0b), Some(Ok(2)));
+        let key0a = Key::from([0x0; 32]);
+        let key1a = key0a + 1337_u64;
+        let key2a = key0a + 42_u64;
+        // let key3a = key0a + 52_u64;
+        // let key2b = key3a - 10_u64;
+        // let key1b = key2b - 42_u64;
+        // let key0b = key1b + 2000_u64 - 663_u64; // same as key1a
+        env::set_contract_storage(&key0a, &1);
+        env::set_contract_storage(&key1a, &2);
+        env::set_contract_storage(&key2a, &3);
+        // assert_eq!(env::get_contract_storage::<i32>(&key2b), Some(Ok(3)));
+        // assert_eq!(env::get_contract_storage::<i32>(&key1b), Some(Ok(1)));
+        // assert_eq!(env::get_contract_storage::<i32>(&key0b), Some(Ok(2)));
         Ok(())
     })
 }
diff --git a/core/src/storage2/alloc/boxed/tests.rs b/core/src/storage2/alloc/boxed/tests.rs
index a331681d39..a6662574e6 100644
--- a/core/src/storage2/alloc/boxed/tests.rs
+++ b/core/src/storage2/alloc/boxed/tests.rs
@@ -108,7 +108,7 @@ fn spread_layout_push_pull_works() {
     run_test(|_| {
         let b1 = StorageBox::new(b'A');
         assert_eq!(*b1, b'A');
-        let root_key = Key([0x42; 32]);
+        let root_key = Key::from([0x42; 32]);
         SpreadLayout::push_spread(&b1, &mut KeyPtr::from(root_key));
         // Now load another instance of storage box from the same key and check
         // if both instances are equal:
@@ -127,7 +127,7 @@ fn spread_layout_clear_works() {
     run_test(|_| {
         let b1 = StorageBox::new(b'A');
         assert_eq!(*b1, b'A');
-        let root_key = Key([0x42; 32]);
+        let root_key = Key::from([0x42; 32]);
         // Manually clear the storage of `b1`. Then another load from the same
         // key region should panic since the entry is empty:
         SpreadLayout::push_spread(&b1, &mut KeyPtr::from(root_key));
@@ -146,7 +146,7 @@ fn packed_layout_works() {
         let p1 = Pack::new((StorageBox::new(b'A'), StorageBox::new([0x01; 4])));
         assert_eq!(*p1.0, b'A');
         assert_eq!(*p1.1, [0x01; 4]);
-        let root_key = Key([0x42; 32]);
+        let root_key = Key::from([0x42; 32]);
         SpreadLayout::push_spread(&p1, &mut KeyPtr::from(root_key));
         // Now load another instance of storage box from the same key and check
         // if both instances are equal:
@@ -165,7 +165,7 @@ fn recursive_pull_push_works() {
     run_test(|_| {
         let rec1 = StorageBox::new(StorageBox::new(b'A'));
         assert_eq!(**rec1, b'A');
-        let root_key = Key([0x42; 32]);
+        let root_key = Key::from([0x42; 32]);
         SpreadLayout::push_spread(&rec1, &mut KeyPtr::from(root_key));
         // Now load another instance of storage box from the same key and check
         // if both instances are equal:
@@ -185,7 +185,7 @@ fn recursive_clear_works() {
     run_test(|_| {
         let rec1 = StorageBox::new(StorageBox::new(b'A'));
         assert_eq!(**rec1, b'A');
-        let root_key = Key([0x42; 32]);
+        let root_key = Key::from([0x42; 32]);
         // Manually clear the storage of `rec1`. Then another load from the same
         // key region should panic since the entry is empty:
         SpreadLayout::push_spread(&rec1, &mut KeyPtr::from(root_key));
@@ -204,7 +204,7 @@ fn recursive_clear_works() {
 fn double_free_panics() {
     run_test(|_| {
         let b1 = StorageBox::new(b'A');
-        let root_key = Key([0x42; 32]);
+        let root_key = Key::from([0x42; 32]);
         // Manually clear the storage of `rec1`. Then another load from the same
         // key region should panic since the entry is empty:
         SpreadLayout::push_spread(&b1, &mut KeyPtr::from(root_key));
diff --git a/core/src/storage2/alloc/tests.rs b/core/src/storage2/alloc/tests.rs
index c8731463f9..de397e7aee 100644
--- a/core/src/storage2/alloc/tests.rs
+++ b/core/src/storage2/alloc/tests.rs
@@ -142,7 +142,7 @@ fn spread_layout_alloc_setup() -> DynamicAllocator {
 fn spread_pull_push_works() {
     run_default_test(|| {
         let mut alloc = spread_layout_alloc_setup();
-        let root_key = Key([0x77; 32]);
+        let root_key = Key::from([0x77; 32]);
         // Push the current state of the dynamic storage allocator to the storage:
         SpreadLayout::push_spread(&alloc, &mut KeyPtr::from(root_key));
         // Now check if the new allocations are filling the freed ones:
@@ -164,7 +164,7 @@ fn spread_pull_push_works() {
 fn spread_clear_works() {
     run_default_test(|| {
         let alloc = spread_layout_alloc_setup();
-        let root_key = Key([0x42; 32]);
+        let root_key = Key::from([0x42; 32]);
         // Push the current state of the dynamic storage allocator to the storage:
         SpreadLayout::push_spread(&alloc, &mut KeyPtr::from(root_key));
         // Pull another instance of the storage allocator from storage,
@@ -195,7 +195,7 @@ fn test_call_setup_works() {
         let mut allocator = DynamicAllocator::default();
         assert_eq!(allocator.alloc(), DynamicAllocation(0));
         assert_eq!(allocator.alloc(), DynamicAllocation(1));
-        let root_key = Key([0xFE; 32]);
+        let root_key = Key::from([0xFE; 32]);
         SpreadLayout::push_spread(&allocator, &mut KeyPtr::from(root_key));
         alloc::initialize(ContractPhase::Call);
         assert_eq!(alloc(), DynamicAllocation(2));
diff --git a/core/src/storage2/collections/bitstash/tests.rs b/core/src/storage2/collections/bitstash/tests.rs
index 66b43644c1..c6123dc806 100644
--- a/core/src/storage2/collections/bitstash/tests.rs
+++ b/core/src/storage2/collections/bitstash/tests.rs
@@ -131,7 +131,7 @@ fn take_refill_rev_works() {
 fn spread_layout_push_pull_works() {
     env::test::run_test::<env::DefaultEnvTypes, _>(|_| {
         let default = filled_bitstash();
-        let root_key = Key([0x42; 32]);
+        let root_key = Key::from([0x42; 32]);
         SpreadLayout::push_spread(&default, &mut KeyPtr::from(root_key));
         let pulled = <BitStash as SpreadLayout>::pull_spread(&mut KeyPtr::from(root_key));
         assert_eq!(default, pulled);
@@ -149,7 +149,7 @@ fn spread_layout_clear_works() {
         // Then load a valid instance, check it and clear its associated storage.
         // Afterwards load the invalid instance from the same storage region
         // and try to interact with it which is expected to fail.
-        let root_key = Key([0x42; 32]);
+        let root_key = Key::from([0x42; 32]);
         SpreadLayout::push_spread(&default, &mut KeyPtr::from(root_key));
         let pulled = <BitStash as SpreadLayout>::pull_spread(&mut KeyPtr::from(root_key));
         assert_eq!(default, pulled);
diff --git a/core/src/storage2/collections/bitvec/tests.rs b/core/src/storage2/collections/bitvec/tests.rs
index 9a163487a4..a812f20855 100644
--- a/core/src/storage2/collections/bitvec/tests.rs
+++ b/core/src/storage2/collections/bitvec/tests.rs
@@ -183,7 +183,7 @@ fn pop_works() {
 fn spread_layout_push_pull_works() -> env::Result<()> {
     env::test::run_test::<env::DefaultEnvTypes, _>(|_| {
         let bv1 = bitvec_600();
-        let root_key = Key([0x42; 32]);
+        let root_key = Key::from([0x42; 32]);
         SpreadLayout::push_spread(&bv1, &mut KeyPtr::from(root_key));
         // Load the pushed storage vector into another instance and check that
         // both instances are equal:
@@ -199,7 +199,7 @@ fn spread_layout_push_pull_works() -> env::Result<()> {
 fn spread_layout_clear_works() {
     env::test::run_test::<env::DefaultEnvTypes, _>(|_| {
         let bv1 = bitvec_600();
-        let root_key = Key([0x42; 32]);
+        let root_key = Key::from([0x42; 32]);
         SpreadLayout::push_spread(&bv1, &mut KeyPtr::from(root_key));
         // It has already been asserted that a valid instance can be pulled
         // from contract storage after a push to the same storage region.
diff --git a/core/src/storage2/collections/hashmap/tests.rs b/core/src/storage2/collections/hashmap/tests.rs
index f9d9034632..d8f7295e59 100644
--- a/core/src/storage2/collections/hashmap/tests.rs
+++ b/core/src/storage2/collections/hashmap/tests.rs
@@ -290,7 +290,7 @@ fn spread_layout_push_pull_works() -> env::Result<()> {
             .iter()
             .copied()
             .collect::<StorageHashMap<u8, i32>>();
-        let root_key = Key([0x42; 32]);
+        let root_key = Key::from([0x42; 32]);
         SpreadLayout::push_spread(&hmap1, &mut KeyPtr::from(root_key));
         // Load the pushed storage vector into another instance and check that
         // both instances are equal:
@@ -310,7 +310,7 @@ fn spread_layout_clear_works() {
             .iter()
             .copied()
             .collect::<StorageHashMap<u8, i32>>();
-        let root_key = Key([0x42; 32]);
+        let root_key = Key::from([0x42; 32]);
         SpreadLayout::push_spread(&hmap1, &mut KeyPtr::from(root_key));
         // It has already been asserted that a valid instance can be pulled
         // from contract storage after a push to the same storage region.
diff --git a/core/src/storage2/collections/smallvec/tests.rs b/core/src/storage2/collections/smallvec/tests.rs
index 015711663a..04d0c06a36 100644
--- a/core/src/storage2/collections/smallvec/tests.rs
+++ b/core/src/storage2/collections/smallvec/tests.rs
@@ -366,7 +366,7 @@ fn swap_remove_drop_works() {
 fn spread_layout_push_pull_works() -> env::Result<()> {
     env::test::run_test::<env::DefaultEnvTypes, _>(|_| {
         let vec1 = vec_from_slice(&[b'a', b'b', b'c', b'd']);
-        let root_key = Key([0x42; 32]);
+        let root_key = Key::from([0x42; 32]);
         SpreadLayout::push_spread(&vec1, &mut KeyPtr::from(root_key));
         // Load the pushed storage vector into another instance and check that
         // both instances are equal:
@@ -382,7 +382,7 @@ fn spread_layout_push_pull_works() -> env::Result<()> {
 fn spread_layout_clear_works() {
     env::test::run_test::<env::DefaultEnvTypes, _>(|_| {
         let vec1 = vec_from_slice(&[b'a', b'b', b'c', b'd']);
-        let root_key = Key([0x42; 32]);
+        let root_key = Key::from([0x42; 32]);
         SpreadLayout::push_spread(&vec1, &mut KeyPtr::from(root_key));
         // It has already been asserted that a valid instance can be pulled
         // from contract storage after a push to the same storage region.
diff --git a/core/src/storage2/collections/stash/tests.rs b/core/src/storage2/collections/stash/tests.rs
index cfd500cd79..2fb50bd286 100644
--- a/core/src/storage2/collections/stash/tests.rs
+++ b/core/src/storage2/collections/stash/tests.rs
@@ -655,7 +655,7 @@ fn take_rev_order_works() {
 fn spread_layout_push_pull_works() -> env::Result<()> {
     env::test::run_test::<env::DefaultEnvTypes, _>(|_| {
         let stash1 = create_holey_stash();
-        let root_key = Key([0x42; 32]);
+        let root_key = Key::from([0x42; 32]);
         SpreadLayout::push_spread(&stash1, &mut KeyPtr::from(root_key));
         // Load the pushed storage vector into another instance and check that
         // both instances are equal:
@@ -671,7 +671,7 @@ fn spread_layout_push_pull_works() -> env::Result<()> {
 fn spread_layout_clear_works() {
     env::test::run_test::<env::DefaultEnvTypes, _>(|_| {
         let stash1 = create_holey_stash();
-        let root_key = Key([0x42; 32]);
+        let root_key = Key::from([0x42; 32]);
         SpreadLayout::push_spread(&stash1, &mut KeyPtr::from(root_key));
         // It has already been asserted that a valid instance can be pulled
         // from contract storage after a push to the same storage region.
diff --git a/core/src/storage2/collections/vec/tests.rs b/core/src/storage2/collections/vec/tests.rs
index f964e9589a..8a5ade271f 100644
--- a/core/src/storage2/collections/vec/tests.rs
+++ b/core/src/storage2/collections/vec/tests.rs
@@ -361,7 +361,7 @@ fn swap_remove_drop_works() {
 fn spread_layout_push_pull_works() -> env::Result<()> {
     env::test::run_test::<env::DefaultEnvTypes, _>(|_| {
         let vec1 = vec_from_slice(&[b'a', b'b', b'c', b'd']);
-        let root_key = Key([0x42; 32]);
+        let root_key = Key::from([0x42; 32]);
         SpreadLayout::push_spread(&vec1, &mut KeyPtr::from(root_key));
         // Load the pushed storage vector into another instance and check that
         // both instances are equal:
@@ -377,7 +377,7 @@ fn spread_layout_push_pull_works() -> env::Result<()> {
 fn spread_layout_clear_works() {
     env::test::run_test::<env::DefaultEnvTypes, _>(|_| {
         let vec1 = vec_from_slice(&[b'a', b'b', b'c', b'd']);
-        let root_key = Key([0x42; 32]);
+        let root_key = Key::from([0x42; 32]);
         SpreadLayout::push_spread(&vec1, &mut KeyPtr::from(root_key));
         // It has already been asserted that a valid instance can be pulled
         // from contract storage after a push to the same storage region.