diff --git a/src/core/enums/expression.ts b/src/core/enums/expression.ts index f56aab4..371f2ba 100644 --- a/src/core/enums/expression.ts +++ b/src/core/enums/expression.ts @@ -40,6 +40,12 @@ export enum ExpressionAtom { isVariant = 'isVariant', cases_arg = 'cases_arg', variant_arg = 'variant_arg', + // Crypto + blake2b = 'blake2b', + sha256 = 'sha256', + sha512 = 'sha512', + sha3 = 'sha3', + keccak = 'keccak', // Generic isNat = 'isNat', contains = 'contains', diff --git a/src/expression/crypto.ts b/src/expression/crypto.ts new file mode 100644 index 0000000..c94e295 --- /dev/null +++ b/src/expression/crypto.ts @@ -0,0 +1,93 @@ +import { LineInfo } from '../misc/utils'; +import { IExpression } from '../typings/expression'; +import { Expression } from '../core/expression'; +import ExpressionAtom from '../core/enums/expression'; + +/** + * Compute a Blake2B cryptographic hash + * + * ```typescript + * BLAKE2B(Bytes("0x01")); + * ``` + * + * @category | Crypto + * + * @param bytes An expression that evaluates to a bytes value. + * @param {LineInfo} line Source code line information (Used in error messages) + * + * @returns {IExpression} An expression + */ +export const BLAKE2B = (bytes: IExpression, line = new LineInfo()) => + new Expression(ExpressionAtom.blake2b, bytes, line); + +/** + * Compute a SHA-256 cryptographic hash + * + * ```typescript + * SHA256(Bytes("0x01")); + * ``` + * + * @category | Crypto + * + * @param bytes An expression that evaluates to a bytes value. + * @param {LineInfo} line Source code line information (Used in error messages) + * + * @returns {IExpression} An expression + */ +export const SHA256 = (bytes: IExpression, line = new LineInfo()) => new Expression(ExpressionAtom.sha256, bytes, line); + +/** + * Compute a SHA-512 cryptographic hash + * + * ```typescript + * SHA512(Bytes("0x01")); + * ``` + * + * @category | Crypto + * + * @param bytes An expression that evaluates to a bytes value. + * @param {LineInfo} line Source code line information (Used in error messages) + * + * @returns {IExpression} An expression + */ +export const SHA512 = (bytes: IExpression, line = new LineInfo()) => new Expression(ExpressionAtom.sha512, bytes, line); + +/** + * Compute a SHA3-256 cryptographic hash + * + * ```typescript + * SHA3(Bytes("0x01")); + * ``` + * + * @category | Crypto + * + * @param bytes An expression that evaluates to a bytes value. + * @param {LineInfo} line Source code line information (Used in error messages) + * + * @returns {IExpression} An expression + */ +export const SHA3 = (bytes: IExpression, line = new LineInfo()) => new Expression(ExpressionAtom.sha3, bytes, line); + +/** + * Compute a Keccak-256 cryptographic hash + * + * ```typescript + * KECCAK(Bytes("0x01")); + * ``` + * + * @category | Crypto + * + * @param bytes An expression that evaluates to a bytes value. + * @param {LineInfo} line Source code line information (Used in error messages) + * + * @returns {IExpression} An expression + */ +export const KECCAK = (bytes: IExpression, line = new LineInfo()) => new Expression(ExpressionAtom.keccak, bytes, line); + +export const Crypto = { + BLAKE2B, + SHA256, + SHA512, + SHA3, + KECCAK, +}; diff --git a/src/expression/index.ts b/src/expression/index.ts index a499742..4930ecf 100644 --- a/src/expression/index.ts +++ b/src/expression/index.ts @@ -1,6 +1,7 @@ export * from './blockchain_properties'; export * from './comparison'; export * from './contract'; +export * from './crypto'; export * from './equality'; export * from './list'; export * from './literal'; diff --git a/tests/distributables/commonjs.cjs b/tests/distributables/commonjs.cjs index 8b39795..d5a8c33 100644 --- a/tests/distributables/commonjs.cjs +++ b/tests/distributables/commonjs.cjs @@ -17,87 +17,112 @@ const contract = new Contract().setStorage(Nat(0)).addEntrypoint( ]), ); -assert.deepEqual(SmartML.compileContract(contract), [ - { - prim: 'storage', - args: [ - { - prim: 'nat', - }, - ], - }, - { - prim: 'parameter', - args: [ - { - prim: 'nat', - annots: ['%ep1'], - }, - ], - }, - { - prim: 'code', - args: [ - [ +assert.deepEqual(SmartML.compileContract(contract), { + micheline: + 'parameter (nat %ep1);\n' + + 'storage nat;\n' + + 'code\n' + + ' {\n' + + ' CAR; # @parameter\n' + + ' # == ep1 ==\n' + + ` # some_address = sp.local("some_address", sp.address('tz1')) # @parameter\n` + + ' PUSH address "tz1"; # address : @parameter\n' + + " # sp.verify(some_address.value == sp.sender, 'Not Admin!') # address : @parameter\n" + + ' SENDER; # @sender : address : @parameter\n' + + ' COMPARE; # int : @parameter\n' + + ' EQ; # bool : @parameter\n' + + ' IF\n' + + ' {}\n' + + ' {\n' + + ' PUSH string "Not Admin!"; # string : @parameter\n' + + ' FAILWITH; # FAILED\n' + + ' }; # @parameter\n' + + ' # self.data = params # @parameter\n' + + ' NIL operation; # list operation : @parameter\n' + + ' PAIR; # pair (list operation) @parameter\n' + + ' };', + json: [ + { + prim: 'storage', + args: [ { - prim: 'CAR', - }, - { - prim: 'PUSH', - args: [ - { - prim: 'address', - }, - { - string: 'tz1', - }, - ], - }, - { - prim: 'SENDER', - }, - { - prim: 'COMPARE', + prim: 'nat', }, + ], + }, + { + prim: 'parameter', + args: [ { - prim: 'EQ', + prim: 'nat', + annots: ['%ep1'], }, - { - prim: 'IF', - args: [ - [], - [ + ], + }, + { + prim: 'code', + args: [ + [ + { + prim: 'CAR', + }, + { + prim: 'PUSH', + args: [ { - prim: 'PUSH', - args: [ - { - prim: 'string', - }, - { - string: 'Not Admin!', - }, - ], + prim: 'address', }, { - prim: 'FAILWITH', + string: 'tz1', }, ], - ], - }, - { - prim: 'NIL', - args: [ - { - prim: 'operation', - }, - ], - }, - { - prim: 'PAIR', - }, + }, + { + prim: 'SENDER', + }, + { + prim: 'COMPARE', + }, + { + prim: 'EQ', + }, + { + prim: 'IF', + args: [ + [], + [ + { + prim: 'PUSH', + args: [ + { + prim: 'string', + }, + { + string: 'Not Admin!', + }, + ], + }, + { + prim: 'FAILWITH', + }, + ], + ], + }, + { + prim: 'NIL', + args: [ + { + prim: 'operation', + }, + ], + }, + { + prim: 'PAIR', + }, + ], ], - ], - }, -]); + }, + ], +}); console.info('[Passes] - CommonJS'); diff --git a/tests/distributables/esm.mjs b/tests/distributables/esm.mjs index cc29830..c4bcdd3 100644 --- a/tests/distributables/esm.mjs +++ b/tests/distributables/esm.mjs @@ -29,87 +29,112 @@ const contract = new Contract().setStorage(Nat(0)).addEntrypoint( ]), ); -assert.deepEqual(SmartML.default.compileContract(contract), [ - { - prim: 'storage', - args: [ - { - prim: 'nat', - }, - ], - }, - { - prim: 'parameter', - args: [ - { - prim: 'nat', - annots: ['%ep1'], - }, - ], - }, - { - prim: 'code', - args: [ - [ +assert.deepEqual(SmartML.default.compileContract(contract), { + micheline: + 'parameter (nat %ep1);\n' + + 'storage nat;\n' + + 'code\n' + + ' {\n' + + ' CAR; # @parameter\n' + + ' # == ep1 ==\n' + + ` # some_address = sp.local("some_address", sp.address('tz1')) # @parameter\n` + + ' PUSH address "tz1"; # address : @parameter\n' + + " # sp.verify(some_address.value == sp.sender, 'Not Admin!') # address : @parameter\n" + + ' SENDER; # @sender : address : @parameter\n' + + ' COMPARE; # int : @parameter\n' + + ' EQ; # bool : @parameter\n' + + ' IF\n' + + ' {}\n' + + ' {\n' + + ' PUSH string "Not Admin!"; # string : @parameter\n' + + ' FAILWITH; # FAILED\n' + + ' }; # @parameter\n' + + ' # self.data = params # @parameter\n' + + ' NIL operation; # list operation : @parameter\n' + + ' PAIR; # pair (list operation) @parameter\n' + + ' };', + json: [ + { + prim: 'storage', + args: [ { - prim: 'CAR', - }, - { - prim: 'PUSH', - args: [ - { - prim: 'address', - }, - { - string: 'tz1', - }, - ], - }, - { - prim: 'SENDER', - }, - { - prim: 'COMPARE', + prim: 'nat', }, + ], + }, + { + prim: 'parameter', + args: [ { - prim: 'EQ', + prim: 'nat', + annots: ['%ep1'], }, - { - prim: 'IF', - args: [ - [], - [ + ], + }, + { + prim: 'code', + args: [ + [ + { + prim: 'CAR', + }, + { + prim: 'PUSH', + args: [ { - prim: 'PUSH', - args: [ - { - prim: 'string', - }, - { - string: 'Not Admin!', - }, - ], + prim: 'address', }, { - prim: 'FAILWITH', + string: 'tz1', }, ], - ], - }, - { - prim: 'NIL', - args: [ - { - prim: 'operation', - }, - ], - }, - { - prim: 'PAIR', - }, + }, + { + prim: 'SENDER', + }, + { + prim: 'COMPARE', + }, + { + prim: 'EQ', + }, + { + prim: 'IF', + args: [ + [], + [ + { + prim: 'PUSH', + args: [ + { + prim: 'string', + }, + { + string: 'Not Admin!', + }, + ], + }, + { + prim: 'FAILWITH', + }, + ], + ], + }, + { + prim: 'NIL', + args: [ + { + prim: 'operation', + }, + ], + }, + { + prim: 'PAIR', + }, + ], ], - ], - }, -]); + }, + ], +}); console.info('[Passes] - ESM'); diff --git a/tests/expressions/__snapshots__/crypto.test.ts.snap b/tests/expressions/__snapshots__/crypto.test.ts.snap new file mode 100644 index 0000000..a494230 --- /dev/null +++ b/tests/expressions/__snapshots__/crypto.test.ts.snap @@ -0,0 +1,381 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Crypto expressions Hashing BLACK2B 1`] = ` +" + ( + template_id (static_id 0 (\\"crypto.test.ts\\" 10)) + storage (variant \\"None\\" (unit) (\\"crypto.test.ts\\" 11)) + storage_type (()) + messages ((hash_bytes_BLACK2B True False False True (\\"crypto.test.ts\\" 13) ((set_type (params (\\"crypto.test.ts\\" 13)) \\"bytes\\" (\\"crypto.test.ts\\" 18)) (set (data) (variant \\"Some\\" (blake2b (params (\\"crypto.test.ts\\" 13)) (\\"crypto.test.ts\\" 15)) (\\"crypto.test.ts\\" 15)) (\\"crypto.test.ts\\" 15))))) + flags () + privates () + views () + entry_points_layout () + initial_metadata () + balance (literal (mutez 0) (\\"crypto.test.ts\\" 10)) + ) + " +`; + +exports[`Crypto expressions Hashing BLACK2B 2`] = ` +"{ + \\"micheline\\": \\"parameter (bytes %hash_bytes_BLACK2B);\\\\nstorage (option bytes);\\\\ncode\\\\n {\\\\n CAR; # @parameter\\\\n # == hash_bytes_BLACK2B ==\\\\n # self.data = sp.some(sp.blake2b(params)) # @parameter\\\\n BLAKE2B; # bytes\\\\n SOME; # option bytes\\\\n NIL operation; # list operation : option bytes\\\\n PAIR; # pair (list operation) (option bytes)\\\\n };\\", + \\"json\\": [ + { + \\"prim\\": \\"storage\\", + \\"args\\": [ + { + \\"prim\\": \\"option\\", + \\"args\\": [ + { + \\"prim\\": \\"bytes\\" + } + ] + } + ] + }, + { + \\"prim\\": \\"parameter\\", + \\"args\\": [ + { + \\"prim\\": \\"bytes\\", + \\"annots\\": [ + \\"%hash_bytes_BLACK2B\\" + ] + } + ] + }, + { + \\"prim\\": \\"code\\", + \\"args\\": [ + [ + { + \\"prim\\": \\"CAR\\" + }, + { + \\"prim\\": \\"BLAKE2B\\" + }, + { + \\"prim\\": \\"SOME\\" + }, + { + \\"prim\\": \\"NIL\\", + \\"args\\": [ + { + \\"prim\\": \\"operation\\" + } + ] + }, + { + \\"prim\\": \\"PAIR\\" + } + ] + ] + } + ] +}" +`; + +exports[`Crypto expressions Hashing KECCAK 1`] = ` +" + ( + template_id (static_id 0 (\\"crypto.test.ts\\" 21)) + storage (variant \\"None\\" (unit) (\\"crypto.test.ts\\" 22)) + storage_type (()) + messages ((hash_bytes_KECCAK True False False True (\\"crypto.test.ts\\" 24) ((set_type (params (\\"crypto.test.ts\\" 24)) \\"bytes\\" (\\"crypto.test.ts\\" 29)) (set (data) (variant \\"Some\\" (keccak (params (\\"crypto.test.ts\\" 24)) (\\"crypto.test.ts\\" 26)) (\\"crypto.test.ts\\" 26)) (\\"crypto.test.ts\\" 26))))) + flags () + privates () + views () + entry_points_layout () + initial_metadata () + balance (literal (mutez 0) (\\"crypto.test.ts\\" 21)) + ) + " +`; + +exports[`Crypto expressions Hashing KECCAK 2`] = ` +"{ + \\"micheline\\": \\"parameter (bytes %hash_bytes_KECCAK);\\\\nstorage (option bytes);\\\\ncode\\\\n {\\\\n CAR; # @parameter\\\\n # == hash_bytes_KECCAK ==\\\\n # self.data = sp.some(sp.keccak(params)) # @parameter\\\\n KECCAK; # bytes\\\\n SOME; # option bytes\\\\n NIL operation; # list operation : option bytes\\\\n PAIR; # pair (list operation) (option bytes)\\\\n };\\", + \\"json\\": [ + { + \\"prim\\": \\"storage\\", + \\"args\\": [ + { + \\"prim\\": \\"option\\", + \\"args\\": [ + { + \\"prim\\": \\"bytes\\" + } + ] + } + ] + }, + { + \\"prim\\": \\"parameter\\", + \\"args\\": [ + { + \\"prim\\": \\"bytes\\", + \\"annots\\": [ + \\"%hash_bytes_KECCAK\\" + ] + } + ] + }, + { + \\"prim\\": \\"code\\", + \\"args\\": [ + [ + { + \\"prim\\": \\"CAR\\" + }, + { + \\"prim\\": \\"KECCAK\\" + }, + { + \\"prim\\": \\"SOME\\" + }, + { + \\"prim\\": \\"NIL\\", + \\"args\\": [ + { + \\"prim\\": \\"operation\\" + } + ] + }, + { + \\"prim\\": \\"PAIR\\" + } + ] + ] + } + ] +}" +`; + +exports[`Crypto expressions Hashing SHA3 1`] = ` +" + ( + template_id (static_id 0 (\\"crypto.test.ts\\" 54)) + storage (variant \\"None\\" (unit) (\\"crypto.test.ts\\" 55)) + storage_type (()) + messages ((hash_bytes_SHA3 True False False True (\\"crypto.test.ts\\" 57) ((set_type (params (\\"crypto.test.ts\\" 57)) \\"bytes\\" (\\"crypto.test.ts\\" 62)) (set (data) (variant \\"Some\\" (sha3 (params (\\"crypto.test.ts\\" 57)) (\\"crypto.test.ts\\" 59)) (\\"crypto.test.ts\\" 59)) (\\"crypto.test.ts\\" 59))))) + flags () + privates () + views () + entry_points_layout () + initial_metadata () + balance (literal (mutez 0) (\\"crypto.test.ts\\" 54)) + ) + " +`; + +exports[`Crypto expressions Hashing SHA3 2`] = ` +"{ + \\"micheline\\": \\"parameter (bytes %hash_bytes_SHA3);\\\\nstorage (option bytes);\\\\ncode\\\\n {\\\\n CAR; # @parameter\\\\n # == hash_bytes_SHA3 ==\\\\n # self.data = sp.some(sp.sha3(params)) # @parameter\\\\n SHA3; # bytes\\\\n SOME; # option bytes\\\\n NIL operation; # list operation : option bytes\\\\n PAIR; # pair (list operation) (option bytes)\\\\n };\\", + \\"json\\": [ + { + \\"prim\\": \\"storage\\", + \\"args\\": [ + { + \\"prim\\": \\"option\\", + \\"args\\": [ + { + \\"prim\\": \\"bytes\\" + } + ] + } + ] + }, + { + \\"prim\\": \\"parameter\\", + \\"args\\": [ + { + \\"prim\\": \\"bytes\\", + \\"annots\\": [ + \\"%hash_bytes_SHA3\\" + ] + } + ] + }, + { + \\"prim\\": \\"code\\", + \\"args\\": [ + [ + { + \\"prim\\": \\"CAR\\" + }, + { + \\"prim\\": \\"SHA3\\" + }, + { + \\"prim\\": \\"SOME\\" + }, + { + \\"prim\\": \\"NIL\\", + \\"args\\": [ + { + \\"prim\\": \\"operation\\" + } + ] + }, + { + \\"prim\\": \\"PAIR\\" + } + ] + ] + } + ] +}" +`; + +exports[`Crypto expressions Hashing SHA256 1`] = ` +" + ( + template_id (static_id 0 (\\"crypto.test.ts\\" 32)) + storage (variant \\"None\\" (unit) (\\"crypto.test.ts\\" 33)) + storage_type (()) + messages ((hash_bytes_SHA256 True False False True (\\"crypto.test.ts\\" 35) ((set_type (params (\\"crypto.test.ts\\" 35)) \\"bytes\\" (\\"crypto.test.ts\\" 40)) (set (data) (variant \\"Some\\" (sha256 (params (\\"crypto.test.ts\\" 35)) (\\"crypto.test.ts\\" 37)) (\\"crypto.test.ts\\" 37)) (\\"crypto.test.ts\\" 37))))) + flags () + privates () + views () + entry_points_layout () + initial_metadata () + balance (literal (mutez 0) (\\"crypto.test.ts\\" 32)) + ) + " +`; + +exports[`Crypto expressions Hashing SHA256 2`] = ` +"{ + \\"micheline\\": \\"parameter (bytes %hash_bytes_SHA256);\\\\nstorage (option bytes);\\\\ncode\\\\n {\\\\n CAR; # @parameter\\\\n # == hash_bytes_SHA256 ==\\\\n # self.data = sp.some(sp.sha256(params)) # @parameter\\\\n SHA256; # bytes\\\\n SOME; # option bytes\\\\n NIL operation; # list operation : option bytes\\\\n PAIR; # pair (list operation) (option bytes)\\\\n };\\", + \\"json\\": [ + { + \\"prim\\": \\"storage\\", + \\"args\\": [ + { + \\"prim\\": \\"option\\", + \\"args\\": [ + { + \\"prim\\": \\"bytes\\" + } + ] + } + ] + }, + { + \\"prim\\": \\"parameter\\", + \\"args\\": [ + { + \\"prim\\": \\"bytes\\", + \\"annots\\": [ + \\"%hash_bytes_SHA256\\" + ] + } + ] + }, + { + \\"prim\\": \\"code\\", + \\"args\\": [ + [ + { + \\"prim\\": \\"CAR\\" + }, + { + \\"prim\\": \\"SHA256\\" + }, + { + \\"prim\\": \\"SOME\\" + }, + { + \\"prim\\": \\"NIL\\", + \\"args\\": [ + { + \\"prim\\": \\"operation\\" + } + ] + }, + { + \\"prim\\": \\"PAIR\\" + } + ] + ] + } + ] +}" +`; + +exports[`Crypto expressions Hashing SHA512 1`] = ` +" + ( + template_id (static_id 0 (\\"crypto.test.ts\\" 43)) + storage (variant \\"None\\" (unit) (\\"crypto.test.ts\\" 44)) + storage_type (()) + messages ((hash_bytes_SHA512 True False False True (\\"crypto.test.ts\\" 46) ((set_type (params (\\"crypto.test.ts\\" 46)) \\"bytes\\" (\\"crypto.test.ts\\" 51)) (set (data) (variant \\"Some\\" (sha512 (params (\\"crypto.test.ts\\" 46)) (\\"crypto.test.ts\\" 48)) (\\"crypto.test.ts\\" 48)) (\\"crypto.test.ts\\" 48))))) + flags () + privates () + views () + entry_points_layout () + initial_metadata () + balance (literal (mutez 0) (\\"crypto.test.ts\\" 43)) + ) + " +`; + +exports[`Crypto expressions Hashing SHA512 2`] = ` +"{ + \\"micheline\\": \\"parameter (bytes %hash_bytes_SHA512);\\\\nstorage (option bytes);\\\\ncode\\\\n {\\\\n CAR; # @parameter\\\\n # == hash_bytes_SHA512 ==\\\\n # self.data = sp.some(sp.sha512(params)) # @parameter\\\\n SHA512; # bytes\\\\n SOME; # option bytes\\\\n NIL operation; # list operation : option bytes\\\\n PAIR; # pair (list operation) (option bytes)\\\\n };\\", + \\"json\\": [ + { + \\"prim\\": \\"storage\\", + \\"args\\": [ + { + \\"prim\\": \\"option\\", + \\"args\\": [ + { + \\"prim\\": \\"bytes\\" + } + ] + } + ] + }, + { + \\"prim\\": \\"parameter\\", + \\"args\\": [ + { + \\"prim\\": \\"bytes\\", + \\"annots\\": [ + \\"%hash_bytes_SHA512\\" + ] + } + ] + }, + { + \\"prim\\": \\"code\\", + \\"args\\": [ + [ + { + \\"prim\\": \\"CAR\\" + }, + { + \\"prim\\": \\"SHA512\\" + }, + { + \\"prim\\": \\"SOME\\" + }, + { + \\"prim\\": \\"NIL\\", + \\"args\\": [ + { + \\"prim\\": \\"operation\\" + } + ] + }, + { + \\"prim\\": \\"PAIR\\" + } + ] + ] + } + ] +}" +`; diff --git a/tests/expressions/crypto.test.ts b/tests/expressions/crypto.test.ts new file mode 100644 index 0000000..568d554 --- /dev/null +++ b/tests/expressions/crypto.test.ts @@ -0,0 +1,65 @@ +import { BLAKE2B, ContractStorage, KECCAK, None, SHA256, SHA3, SHA512, Some } from '../../src/expression'; +import { Contract, EntryPoint } from '../../src/core'; +import { verifyContractCompilationOutput } from '../util'; +import { SetValue } from '../../src/statement'; +import { TBytes } from '../../src/type'; + +describe('Crypto expressions', () => { + describe('Hashing', () => { + it('BLACK2B', () => { + const contract = new Contract() + .setStorage(None()) + .addEntrypoint( + new EntryPoint('hash_bytes_BLACK2B') + .setInputType(TBytes()) + .code((arg) => [SetValue(ContractStorage(), Some(BLAKE2B(arg)))]), + ); + + verifyContractCompilationOutput(contract); + }); + it('KECCAK', () => { + const contract = new Contract() + .setStorage(None()) + .addEntrypoint( + new EntryPoint('hash_bytes_KECCAK') + .setInputType(TBytes()) + .code((arg) => [SetValue(ContractStorage(), Some(KECCAK(arg)))]), + ); + + verifyContractCompilationOutput(contract); + }); + it('SHA256', () => { + const contract = new Contract() + .setStorage(None()) + .addEntrypoint( + new EntryPoint('hash_bytes_SHA256') + .setInputType(TBytes()) + .code((arg) => [SetValue(ContractStorage(), Some(SHA256(arg)))]), + ); + + verifyContractCompilationOutput(contract); + }); + it('SHA512', () => { + const contract = new Contract() + .setStorage(None()) + .addEntrypoint( + new EntryPoint('hash_bytes_SHA512') + .setInputType(TBytes()) + .code((arg) => [SetValue(ContractStorage(), Some(SHA512(arg)))]), + ); + + verifyContractCompilationOutput(contract); + }); + it('SHA3', () => { + const contract = new Contract() + .setStorage(None()) + .addEntrypoint( + new EntryPoint('hash_bytes_SHA3') + .setInputType(TBytes()) + .code((arg) => [SetValue(ContractStorage(), Some(SHA3(arg)))]), + ); + + verifyContractCompilationOutput(contract); + }); + }); +});