diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -295,7 +295,6 @@
     switch (opcode) {
         case OP_CAT:
         case OP_SPLIT:
-        case OP_NUM2BIN:
         case OP_INVERT:
         case OP_2MUL:
         case OP_2DIV:
@@ -310,6 +309,7 @@
         case OP_AND:
         case OP_OR:
         case OP_XOR:
+        case OP_NUM2BIN:
         case OP_BIN2NUM:
             // Opcodes that have been reenabled.
             if ((flags & SCRIPT_ENABLE_MONOLITH_OPCODES) == 0) {
@@ -1250,6 +1250,51 @@
                     //
                     // Conversion operations
                     //
+                    case OP_NUM2BIN: {
+                        // (in size -- out)
+                        if (stack.size() < 2) {
+                            return set_error(
+                                serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
+                        }
+
+                        uint64_t size =
+                            CScriptNum(stacktop(-1), fRequireMinimal).getint();
+                        if (size > MAX_SCRIPT_ELEMENT_SIZE) {
+                            return set_error(serror, SCRIPT_ERR_PUSH_SIZE);
+                        }
+
+                        popstack(stack);
+                        valtype &rawnum = stacktop(-1);
+
+                        // Try to see if we can fit that number in the number of
+                        // byte requested.
+                        CScriptNum::MinimallyEncode(rawnum);
+                        if (rawnum.size() > size) {
+                            // We definitively cannot.
+                            return set_error(serror,
+                                             SCRIPT_ERR_IMPOSSIBLE_ENCODING);
+                        }
+
+                        // We already have an element of the right size, we
+                        // don't need to do anything.
+                        if (rawnum.size() == size) {
+                            break;
+                        }
+
+                        uint8_t signbit = 0x00;
+                        if (rawnum.size() > 0) {
+                            signbit = rawnum.back() & 0x80;
+                            rawnum[rawnum.size() - 1] &= 0x7f;
+                        }
+
+                        rawnum.reserve(size);
+                        while (rawnum.size() < size - 1) {
+                            rawnum.push_back(0x00);
+                        }
+
+                        rawnum.push_back(signbit);
+                    } break;
+
                     case OP_BIN2NUM: {
                         // (in -- out)
                         if (stack.size() < 1) {
diff --git a/src/script/script_error.h b/src/script/script_error.h
--- a/src/script/script_error.h
+++ b/src/script/script_error.h
@@ -23,6 +23,7 @@
     /* Operands checks */
     SCRIPT_ERR_INVALID_OPERAND_SIZE,
     SCRIPT_ERR_INVALID_NUMBER_RANGE,
+    SCRIPT_ERR_IMPOSSIBLE_ENCODING,
 
     /* Failed verify operations */
     SCRIPT_ERR_VERIFY,
diff --git a/src/script/script_error.cpp b/src/script/script_error.cpp
--- a/src/script/script_error.cpp
+++ b/src/script/script_error.cpp
@@ -39,6 +39,8 @@
         case SCRIPT_ERR_INVALID_NUMBER_RANGE:
             return "Given operand is not a number within the valid range "
                    "[-2^31...2^31]";
+        case SCRIPT_ERR_IMPOSSIBLE_ENCODING:
+            return "The requested encoding is impossible to satisfy";
         case SCRIPT_ERR_BAD_OPCODE:
             return "Opcode missing or not understood";
         case SCRIPT_ERR_DISABLED_OPCODE:
diff --git a/src/test/data/script_tests.json b/src/test/data/script_tests.json
--- a/src/test/data/script_tests.json
+++ b/src/test/data/script_tests.json
@@ -826,18 +826,35 @@
 ["'abc' 1 1 0", "IF SPLIT ELSE 1 ENDIF", "P2SH,STRICTENC", "DISABLED_OPCODE", "SPLIT disabled"],
 ["'abc' 1 1 0", "IF SPLIT ELSE 1 ENDIF", "P2SH,STRICTENC,MONOLITH_OPCODES", "DISABLED_OPCODE", "SPLIT disabled"],
 ["'abc' 2 0", "IF NUM2BIN ELSE 1 ENDIF", "P2SH,STRICTENC", "DISABLED_OPCODE", "NUM2BIN disabled"],
-["'abc' 2 0", "IF NUM2BIN ELSE 1 ENDIF", "P2SH,STRICTENC,MONOLITH_OPCODES", "DISABLED_OPCODE", "NUM2BIN disabled"],
+["'abc' 2 0", "IF NUM2BIN ELSE 1 ENDIF", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "NUM2BIN enabled"],
 ["'abc' 2 0", "IF BIN2NUM ELSE 1 ENDIF", "P2SH,STRICTENC", "DISABLED_OPCODE", "BIN2NUM disabled"],
 ["'abc' 2 0", "IF BIN2NUM ELSE 1 ENDIF", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "BIN2NUM enabled"],
 
+["NUM2BIN"],
+["", "NUM2BIN 0 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "INVALID_STACK_OPERATION", "NUM2BIN, empty stack"],
+["0", "NUM2BIN 0 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "INVALID_STACK_OPERATION", "NUM2BIN, one parameter"],
+["0 0", "NUM2BIN 0 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "NUM2BIN, canonical argument "],
+["0 1", "NUM2BIN 0x01 0x00 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "NUM2BIN, zero extend"],
+["0 7", "NUM2BIN 0x01 0x00000000000000 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "NUM2BIN, zero extend"],
+["1 1", "NUM2BIN 1 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "NUM2BIN, canonical argument "],
+["-42 1", "NUM2BIN -42 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "NUM2BIN, canonical argument "],
+["-42 2", "NUM2BIN 0x02 0x2a80 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "NUM2BIN, canonical argument "],
+["-42 10", "NUM2BIN 0x02 0x2a000000000000000080 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "NUM2BIN, large materialization"],
+["-42 520", "NUM2BIN", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "Pushing 520 bytes is ok"],
+["-42 521", "NUM2BIN", "P2SH,STRICTENC,MONOLITH_OPCODES", "PUSH_SIZE", "Pushing 521 bytes is not"],
+["-42 -3", "NUM2BIN", "P2SH,STRICTENC,MONOLITH_OPCODES", "PUSH_SIZE", "Negative size"],
+["0x05 0xabcdef4280 4", "NUM2BIN 0x04 0xabcdefc2", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "Item size reduction"],
+["0x01 0x80 0", "NUM2BIN 0 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "Negative zero"],
+["0x01 0x80 3", "NUM2BIN 0x03 0x000000 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "Negative zero, larger output"],
+
 ["BIN2NUM"],
 ["", "BIN2NUM 0 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "INVALID_STACK_OPERATION", "BIN2NUM, empty stack"],
-["0", "BIN2NUM 0 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "BIN2NUM, canonical arguement"],
-["1", "BIN2NUM 1 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "BIN2NUM, canonical arguement"],
-["-42", "BIN2NUM -42 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "BIN2NUM, canonical arguement"],
-["0x01 0x00", "BIN2NUM 0 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "BIN2NUM, non-canonical arguement"],
-["0x04 0xffffff7f", "BIN2NUM 2147483647 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "BIN2NUM, maximum size arguement"],
-["0x04 0xffffffff", "BIN2NUM -2147483647 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "BIN2NUM, maximum size arguement"],
+["0", "BIN2NUM 0 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "BIN2NUM, canonical argument "],
+["1", "BIN2NUM 1 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "BIN2NUM, canonical argument "],
+["-42", "BIN2NUM -42 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "BIN2NUM, canonical argument "],
+["0x01 0x00", "BIN2NUM 0 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "BIN2NUM, non-canonical argument "],
+["0x04 0xffffff7f", "BIN2NUM 2147483647 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "BIN2NUM, maximum size argument "],
+["0x04 0xffffffff", "BIN2NUM -2147483647 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "BIN2NUM, maximum size argument "],
 ["0x05 0xffffffff00", "BIN2NUM 2147483647 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "INVALID_NUMBER_RANGE", "BIN2NUM, oversized arguement"],
 ["0x05 0xffffff7f80", "BIN2NUM -2147483647 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "BIN2NUM, non-canonical maximum size arguement"],
 ["0x05 0x0100000000", "BIN2NUM 1 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK"],
diff --git a/src/test/monolith_opcodes.cpp b/src/test/monolith_opcodes.cpp
--- a/src/test/monolith_opcodes.cpp
+++ b/src/test/monolith_opcodes.cpp
@@ -155,6 +155,9 @@
     valtype allzeros(MAX_SCRIPT_ELEMENT_SIZE, 0);
     valtype allones(MAX_SCRIPT_ELEMENT_SIZE, 0xff);
 
+    BOOST_CHECK_EQUAL(allzeros.size(), MAX_SCRIPT_ELEMENT_SIZE);
+    BOOST_CHECK_EQUAL(allones.size(), MAX_SCRIPT_ELEMENT_SIZE);
+
     TestBitwiseOpcodes(allzeros, allzeros, allzeros, allzeros);
     TestBitwiseOpcodes(allzeros, allones, allzeros, allones);
     TestBitwiseOpcodes(allones, allones, allones, allones);
@@ -371,10 +374,39 @@
 /**
  * Type conversion opcodes.
  */
-static void CheckBin2NumOp(const valtype &n, const valtype &expected) {
-    CheckTestResultForAllFlags({n}, CScript() << OP_BIN2NUM, {expected});
+static void CheckTypeConversionOp(const valtype &bin, const valtype &num) {
+    // Check BIN2NUM.
+    CheckTestResultForAllFlags({bin}, CScript() << OP_BIN2NUM, {num});
+
+    // Check NUM2BIN. Negative 0 is rebuilt as regular zero, so we need a tweak.
+    valtype rebuilt_bin{bin};
+    if (num.size() == 0 && bin.size() > 0) {
+        rebuilt_bin[rebuilt_bin.size() - 1] &= 0x7f;
+    }
 
-    // TODO: Check roundtrip with NUM2BIN when NUM2BIN is implemented.
+    CheckTestResultForAllFlags({num}, CScript() << bin.size() << OP_NUM2BIN,
+                               {rebuilt_bin});
+
+    // Check roundtrip with NUM2BIN.
+    CheckTestResultForAllFlags(
+        {bin}, CScript() << OP_BIN2NUM << bin.size() << OP_NUM2BIN,
+        {rebuilt_bin});
+
+    // Grow and shrink back down using NUM2BIN.
+    CheckTestResultForAllFlags({bin},
+                               CScript()
+                                   << MAX_SCRIPT_ELEMENT_SIZE << OP_NUM2BIN
+                                   << bin.size() << OP_NUM2BIN,
+                               {rebuilt_bin});
+    CheckTestResultForAllFlags({num},
+                               CScript()
+                                   << MAX_SCRIPT_ELEMENT_SIZE << OP_NUM2BIN
+                                   << bin.size() << OP_NUM2BIN,
+                               {rebuilt_bin});
+
+    // BIN2NUM is indempotent.
+    CheckTestResultForAllFlags({bin}, CScript() << OP_BIN2NUM << OP_BIN2NUM,
+                               {num});
 }
 
 static void CheckBin2NumError(const std::vector<valtype> &original_stack,
@@ -383,17 +415,23 @@
                           expected_error);
 }
 
+static void CheckNum2BinError(const std::vector<valtype> &original_stack,
+                              ScriptError expected_error) {
+    CheckErrorForAllFlags(original_stack, CScript() << OP_NUM2BIN,
+                          expected_error);
+}
+
 BOOST_AUTO_TEST_CASE(type_conversion_test) {
     valtype empty;
-    CheckBin2NumOp(empty, empty);
+    CheckTypeConversionOp(empty, empty);
 
     valtype paddedzero, paddednegzero;
-    for (size_t i = 0; i <= MAX_SCRIPT_ELEMENT_SIZE; i++) {
-        CheckBin2NumOp(paddedzero, empty);
+    for (size_t i = 0; i < MAX_SCRIPT_ELEMENT_SIZE; i++) {
+        CheckTypeConversionOp(paddedzero, empty);
         paddedzero.push_back(0x00);
 
         paddednegzero.push_back(0x80);
-        CheckBin2NumOp(paddednegzero, empty);
+        CheckTypeConversionOp(paddednegzero, empty);
         paddednegzero[paddednegzero.size() - 1] = 0x00;
     }
 
@@ -401,28 +439,48 @@
     std::vector<uint8_t> k{0x7f}, negk{0xff};
     std::vector<uint8_t> kpadded = k, negkpadded = negk;
     for (size_t i = 0; i < MAX_SCRIPT_ELEMENT_SIZE; i++) {
-        CheckBin2NumOp(kpadded, k);
+        CheckTypeConversionOp(kpadded, k);
         kpadded.push_back(0x00);
 
-        CheckBin2NumOp(negkpadded, negk);
+        CheckTypeConversionOp(negkpadded, negk);
         negkpadded[negkpadded.size() - 1] &= 0x7f;
         negkpadded.push_back(0x80);
     }
 
     // Some known values.
-    CheckBin2NumOp({0xab, 0xcd, 0xef, 0x00}, {0xab, 0xcd, 0xef, 0x00});
-    CheckBin2NumOp({0xab, 0xcd, 0x7f, 0x00}, {0xab, 0xcd, 0x7f});
+    CheckTypeConversionOp({0xab, 0xcd, 0xef, 0x00}, {0xab, 0xcd, 0xef, 0x00});
+    CheckTypeConversionOp({0xab, 0xcd, 0x7f, 0x00}, {0xab, 0xcd, 0x7f});
 
     // Reductions
-    CheckBin2NumOp({0xab, 0xcd, 0xef, 0x42, 0x80}, {0xab, 0xcd, 0xef, 0xc2});
-    CheckBin2NumOp({0xab, 0xcd, 0x7f, 0x42, 0x00}, {0xab, 0xcd, 0x7f, 0x42});
+    CheckTypeConversionOp({0xab, 0xcd, 0xef, 0x42, 0x80},
+                          {0xab, 0xcd, 0xef, 0xc2});
+    CheckTypeConversionOp({0xab, 0xcd, 0x7f, 0x42, 0x00},
+                          {0xab, 0xcd, 0x7f, 0x42});
 
     // Empty stack is an error.
     CheckBin2NumError({}, SCRIPT_ERR_INVALID_STACK_OPERATION);
+    CheckNum2BinError({}, SCRIPT_ERR_INVALID_STACK_OPERATION);
+
+    // NUM2BIN require 2 elements on the stack.
+    CheckNum2BinError({{0x00}}, SCRIPT_ERR_INVALID_STACK_OPERATION);
+
+    // Values that do not fit in 4 bytes are considered out of range for
+    // BIN2NUM.
     CheckBin2NumError({{0xab, 0xcd, 0xef, 0xc2, 0x80}},
                       SCRIPT_ERR_INVALID_NUMBER_RANGE);
     CheckBin2NumError({{0x00, 0x00, 0x00, 0x80, 0x80}},
                       SCRIPT_ERR_INVALID_NUMBER_RANGE);
+
+    // NUM2BIN must not generate oversized push.
+    valtype largezero(MAX_SCRIPT_ELEMENT_SIZE, 0);
+    BOOST_CHECK_EQUAL(largezero.size(), MAX_SCRIPT_ELEMENT_SIZE);
+    CheckTypeConversionOp(largezero, {});
+
+    CheckNum2BinError({{}, {0x09, 0x02}}, SCRIPT_ERR_PUSH_SIZE);
+
+    // Check that the requested encoding is possible.
+    CheckNum2BinError({{0xab, 0xcd, 0xef, 0x80}, {0x03}},
+                      SCRIPT_ERR_IMPOSSIBLE_ENCODING);
 }
 
 BOOST_AUTO_TEST_SUITE_END()