├── .bazelrc ├── .clang-format ├── .github └── CODEOWNERS ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── WORKSPACE ├── mam ├── BUILD ├── api │ ├── BUILD │ ├── api.c │ ├── api.h │ └── tests │ │ ├── BUILD │ │ └── test_api.c ├── defs.h ├── doxy.txt ├── examples │ ├── BUILD │ ├── README.md │ ├── common.c │ ├── common.h │ ├── ntru-key-exchange.c │ ├── recv.c │ ├── send-common.c │ ├── send-common.h │ ├── send-header.c │ ├── send-msg.c │ └── send-packet.c ├── mam │ ├── BUILD │ ├── channel.c │ ├── channel.h │ ├── endpoint.c │ ├── endpoint.h │ ├── message.c │ ├── message.h │ └── tests │ │ ├── BUILD │ │ ├── test_channel.c │ │ ├── test_channel_utils.c │ │ ├── test_channel_utils.h │ │ ├── test_endpoint.c │ │ └── test_message.c ├── mss │ ├── BUILD │ ├── mss.h │ ├── mss_classic.c │ ├── mss_classic.h │ ├── mss_common.c │ ├── mss_common.h │ ├── mss_traversal.c │ ├── mss_traversal.h │ └── tests │ │ ├── BUILD │ │ └── test_mss.c ├── ntru │ ├── BUILD │ ├── ntru.c │ ├── ntru.h │ ├── ntru_types.h │ ├── poly.c │ ├── poly.h │ ├── poly_param.h │ └── tests │ │ ├── BUILD │ │ ├── test_ntru.c │ │ └── test_poly.c ├── pb3 │ ├── BUILD │ ├── pb3.c │ ├── pb3.h │ └── tests │ │ ├── BUILD │ │ └── test_pb3.c ├── prng │ ├── BUILD │ ├── prng.c │ ├── prng.h │ └── tests │ │ ├── BUILD │ │ └── test_prng.c ├── prototype │ ├── BUILD │ ├── mam.c │ ├── mam.h │ ├── mask.c │ ├── mask.h │ └── tests │ │ ├── BUILD │ │ ├── test_mam.c │ │ └── test_mask.c ├── psk │ ├── BUILD │ ├── psk.c │ ├── psk.h │ └── tests │ │ ├── BUILD │ │ └── test_psk.c ├── rep.pdf ├── spec.pdf ├── sponge │ ├── BUILD │ ├── sponge.c │ ├── sponge.h │ ├── spongos.c │ ├── spongos.h │ ├── spongos_types.c │ ├── spongos_types.h │ └── tests │ │ ├── BUILD │ │ ├── test_sponge.c │ │ └── test_spongos.c ├── trits │ ├── BUILD │ ├── buffers.c │ ├── buffers.h │ ├── tests │ │ ├── BUILD │ │ └── test_trits.c │ ├── trits.c │ └── trits.h ├── troika │ ├── BUILD │ ├── tests │ │ ├── BUILD │ │ └── test_troika.c │ ├── troika.c │ └── troika.h └── wots │ ├── BUILD │ ├── tests │ ├── BUILD │ └── test_wots.c │ ├── wots.c │ └── wots.h └── tools ├── buildifier ├── ci_buildifier_check ├── ci_format_check ├── formatter └── hooks ├── autohook.sh ├── pre-commit ├── 01-buildifier-check └── 02-format-check └── scripts ├── buildifier_check └── format_check /.bazelrc: -------------------------------------------------------------------------------- 1 | build --copt -W 2 | build --copt -Wall 3 | build --copt -Wextra 4 | 5 | test --copt='-ggdb3' 6 | 7 | # --config asan: Address sanitizer 8 | build:asan --strip=never 9 | build:asan --copt -DADDRESS_SANITIZER 10 | build:asan --copt -fsanitize=address 11 | build:asan --copt -fno-omit-frame-pointer 12 | build:asan --linkopt -fsanitize=address 13 | 14 | # --config tsan: ThreadSanitizer 15 | build:tsan --strip=never 16 | build:tsan --copt -DTHREAD_SANITIZER 17 | build:tsan --copt -DDYNAMIC_ANNOTATIONS_ENABLED=1 18 | build:tsan --copt -DDYNAMIC_ANNOTATIONS_EXTERNAL_IMPL=1 19 | build:tsan --copt -fsanitize=thread 20 | build:tsan --copt -fno-omit-frame-pointer 21 | build:tsan --linkopt -fsanitize=thread 22 | build:tsan --linkopt -ltsan 23 | 24 | # --config msan: Memory sanitizer 25 | build:msan --strip=never 26 | build:msan --copt -DADDRESS_SANITIZER 27 | build:msan --copt -fsanitize=memory 28 | build:msan --copt -fno-omit-frame-pointer 29 | build:msan --linkopt -fsanitize=memory 30 | 31 | # --config ubsan: Undefined Behavior Sanitizer 32 | build:ubsan --strip=never 33 | build:ubsan --copt -fsanitize=undefined 34 | build:ubsan --copt -fno-omit-frame-pointer 35 | build:ubsan --linkopt -fsanitize=undefined 36 | build:ubsan --linkopt -lubsan 37 | 38 | ### toolchains ### 39 | 40 | build:aarch64 --crosstool_top=@iota_toolchains//tools/aarch64--glibc--bleeding-edge-2018.07-1:toolchain 41 | build:aarch64 --cpu=aarch64 42 | build:aarch64 --host_crosstool_top=@bazel_tools//tools/cpp:toolchain 43 | 44 | build:armv7 --crosstool_top=@iota_toolchains//tools/armv7-eabihf--glibc--bleeding-edge-2018.07-1:toolchain 45 | build:armv7 --cpu=armeabi-v7a 46 | build:armv7 --host_crosstool_top=@bazel_tools//tools/cpp:toolchain 47 | 48 | build:bootlin_i686 --crosstool_top=@iota_toolchains//tools/x86-i686--glibc--bleeding-edge-2018.07-1:toolchain 49 | build:bootlin_i686 --cpu=i686 50 | build:bootlin_i686 --host_crosstool_top=@bazel_tools//tools/cpp:toolchain 51 | 52 | build:bootlin_x86_64_core_i7 --crosstool_top=@iota_toolchains//tools/x86-64-core-i7--glibc--bleeding-edge-2018.07-1:toolchain 53 | build:bootlin_x86_64_core_i7 --cpu=x86_64 54 | build:bootlin_x86_64_core_i7 --host_crosstool_top=@bazel_tools//tools/cpp:toolchain 55 | 56 | build:esp32_64 --crosstool_top=@iota_toolchains//tools/xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a-5.2.0:toolchain 57 | build:esp32_64 --cpu=xtensa 58 | build:esp32_64 --host_crosstool_top=@bazel_tools//tools/cpp:toolchain 59 | 60 | build:emscripten --crosstool_top=@iota_toolchains//tools/emscripten:toolchain 61 | build:emscripten --cpu=emscripten 62 | build:emscripten --host_crosstool_top=@bazel_tools//tools/cpp:toolchain 63 | 64 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: Google 4 | AccessModifierOffset: -1 5 | AlignAfterOpenBracket: Align 6 | AlignConsecutiveAssignments: false 7 | AlignConsecutiveDeclarations: false 8 | AlignEscapedNewlines: Left 9 | AlignOperands: true 10 | AlignTrailingComments: true 11 | AllowAllParametersOfDeclarationOnNextLine: true 12 | AllowShortBlocksOnASingleLine: false 13 | AllowShortCaseLabelsOnASingleLine: false 14 | AllowShortFunctionsOnASingleLine: All 15 | AllowShortIfStatementsOnASingleLine: true 16 | AllowShortLoopsOnASingleLine: true 17 | AlwaysBreakAfterDefinitionReturnType: None 18 | AlwaysBreakAfterReturnType: None 19 | AlwaysBreakBeforeMultilineStrings: true 20 | AlwaysBreakTemplateDeclarations: true 21 | BinPackArguments: true 22 | BinPackParameters: true 23 | BraceWrapping: 24 | AfterClass: false 25 | AfterControlStatement: false 26 | AfterEnum: false 27 | AfterFunction: false 28 | AfterNamespace: false 29 | AfterObjCDeclaration: false 30 | AfterStruct: false 31 | AfterUnion: false 32 | BeforeCatch: false 33 | BeforeElse: false 34 | IndentBraces: false 35 | SplitEmptyFunction: true 36 | SplitEmptyRecord: true 37 | SplitEmptyNamespace: true 38 | BreakBeforeBinaryOperators: None 39 | BreakBeforeBraces: Attach 40 | BreakBeforeInheritanceComma: false 41 | BreakBeforeTernaryOperators: true 42 | BreakConstructorInitializersBeforeComma: false 43 | BreakConstructorInitializers: BeforeColon 44 | BreakAfterJavaFieldAnnotations: false 45 | BreakStringLiterals: true 46 | ColumnLimit: 120 47 | CommentPragmas: '^ IWYU pragma:' 48 | CompactNamespaces: false 49 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 50 | ConstructorInitializerIndentWidth: 4 51 | ContinuationIndentWidth: 4 52 | Cpp11BracedListStyle: true 53 | DerivePointerAlignment: true 54 | DisableFormat: false 55 | ExperimentalAutoDetectBinPacking: false 56 | FixNamespaceComments: true 57 | ForEachMacros: 58 | - foreach 59 | - Q_FOREACH 60 | - BOOST_FOREACH 61 | IncludeCategories: 62 | - Regex: '^<.*\.h>' 63 | Priority: 1 64 | - Regex: '^<.*' 65 | Priority: 2 66 | - Regex: '.*' 67 | Priority: 3 68 | IncludeIsMainRegex: '([-_](test|unittest))?$' 69 | IndentCaseLabels: true 70 | IndentWidth: 2 71 | IndentWrappedFunctionNames: false 72 | JavaScriptQuotes: Leave 73 | JavaScriptWrapImports: true 74 | KeepEmptyLinesAtTheStartOfBlocks: false 75 | MacroBlockBegin: '' 76 | MacroBlockEnd: '' 77 | MaxEmptyLinesToKeep: 1 78 | NamespaceIndentation: None 79 | ObjCBlockIndentWidth: 2 80 | ObjCSpaceAfterProperty: false 81 | ObjCSpaceBeforeProtocolList: false 82 | PenaltyBreakAssignment: 2 83 | PenaltyBreakBeforeFirstCallParameter: 1 84 | PenaltyBreakComment: 300 85 | PenaltyBreakFirstLessLess: 120 86 | PenaltyBreakString: 1000 87 | PenaltyExcessCharacter: 1000000 88 | PenaltyReturnTypeOnItsOwnLine: 200 89 | PointerAlignment: Left 90 | ReflowComments: true 91 | SortIncludes: true 92 | SortUsingDeclarations: true 93 | SpaceAfterCStyleCast: false 94 | SpaceAfterTemplateKeyword: true 95 | SpaceBeforeAssignmentOperators: true 96 | SpaceBeforeParens: ControlStatements 97 | SpaceInEmptyParentheses: false 98 | SpacesBeforeTrailingComments: 2 99 | SpacesInAngles: false 100 | SpacesInContainerLiterals: true 101 | SpacesInCStyleCastParentheses: false 102 | SpacesInParentheses: false 103 | SpacesInSquareBrackets: false 104 | Standard: Auto 105 | TabWidth: 8 106 | UseTab: Never 107 | --- 108 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/about-codeowners/ 2 | # for more details about CODEOWNERS file 3 | 4 | * @iotaledger/entangled 5 | 6 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Help is very welcome. Before making a Pull Request, ensure you have installed requirements and ran `./tools/hooks/autohook.sh install` after initial checkout! 4 | 5 | ## Requirements 6 | 7 | ### [buildifier](https://github.com/bazelbuild/buildtools/tree/master/buildifier) 8 | Buildifier can be installed with `bazel` or `go`. 9 | 10 | **Install with go** 11 | 12 | 1. change directory to `$GOPATH` 13 | 2. run `$ go get github.com/bazelbuild/buildtools/buildifier` 14 | The executable file will be located under `$GOPATH/bin` 15 | 3. create a soft link for global usage, run 16 | `$ sudo ln -s $HOME/go/bin/buildifier /usr/bin/buildifier` 17 | 18 | **Install with bazel** 19 | 20 | 1. clone `bazelbuild/buildtools` repository 21 | `$ git clone https://github.com/bazelbuild/buildtools.git` 22 | 2. change directory to `buildtools` 23 | 3. build it with bazel command, `$ bazel build //buildifier` 24 | The executable file will be located under `path/to/buildtools/bazel-bin` 25 | 4. create a soft link 26 | 27 | ### [clang-format](https://clang.llvm.org/docs/ClangFormat.html) 28 | clang-format can be installed by command: 29 | - Debian/Ubuntu based: `$ sudo apt-get install clang-format` 30 | - OSX: `$ brew install clang-format` 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MAM 2 | 3 | MAM (Masked authenticated messaging) is a trinary messages encryption scheme 4 | that allows for both confidentiality and authenticity based on an original 5 | implementation & specification by apmi.bsu.by 6 | 7 | MAM allows for: 8 | 9 | - Message encryption via NTRU (public key encrytpion) and PSK (Pre-Shared Key) 10 | 11 | - Sending a message to multiple receivers, each having his/her own session key 12 | 13 | - Authenticating a message either via MAC (Integrity) or via MSS signature (Integrity + Authenticity) 14 | 15 | ## MAM components (directories within this repo) 16 | 17 | *API* - Translates MAM messages into Tangle's bundle 18 | 19 | *Examples* - Naive implementation of MAM messaging over 20 | the Tangle that makes use of CClient (https://github.com/iotaledger/entangled/tree/develop/cclient) 21 | 22 | *MAM* - Contains implementation of messages encryption/decryption 23 | 24 | *MSS* - "Merkle Signature Scheme" - this implementation is used to create new channels/endpoints 25 | 26 | *WOTS* - "Winternitz one time signatures" - the underlying signature implementation of the MSS layer 27 | 28 | *NTRU* - Supports an NTRU-style public key encryption scheme. Using NTRU a sender can encrypt session keys with a public key of a recipient. The secret key must be kept in secret. The corresponding public key, on the contrary, is publicly announced. 29 | 30 | *PSK* - Pre-Shared Key (PSK) is a secret key of Authenticated Encryption (AE). It is preliminarily transmitted between the entities and is beyond the scope of MAM. The PSK id is an identifier of a group of recipients who share the same PSK. 31 | 32 | *PRNG* - Pseudo randomness generator based on sponge's hash function 33 | 34 | *PB3* - Encoding implementation used for serialization and by the MAM layer mostly 35 | 36 | *Sponge* - Hash based cryptography based on the Keccack duplex construction (https://keccak.team/sponge_duplex.html) 37 | 38 | *Troika* - Trinary hash function, it's transform function is used as the _Round_ function for the Sponge layer 39 | 40 | *Trits* - utility functions for manipulating trit arrays 41 | 42 | ## How to use it? 43 | 44 | ### Managing PSKs 45 | 46 | The sender creates a PSK by providing a 27-trytes id and a custom trytes nonce, then provides it to recipients. 47 | ``` 48 | mam_psk_t psk; 49 | mam_psk_gen(&psk, &prng, "B9IOSRYXSJPELPKGTG9PJDQC9YS", "PZQZ...AKKEF", 42); 50 | // Provides it to recipients 51 | mam_psk_destroy(&psk); 52 | ``` 53 | 54 | The receiver receives a PSK from a sender and adds it to the API. 55 | ``` 56 | mam_psk_t psk; 57 | // Receives it from sender 58 | mam_api_add_psk(&api, &psk); 59 | mam_psk_destroy(&psk); 60 | ``` 61 | 62 | ## Contributing 63 | 64 | Please read [CONTRIBUTING.md](https://github.com/iotaledger/mam.c/blob/master/CONTRIBUTING.md) for details. 65 | -------------------------------------------------------------------------------- /WORKSPACE: -------------------------------------------------------------------------------- 1 | workspace(name = "org_iota_mam") 2 | 3 | load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") 4 | load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe") 5 | load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") 6 | 7 | git_repository( 8 | name = "org_iota_common", 9 | commit = "c04fcd03f98d07e3d9114dfbd003f4e679ec120d", 10 | remote = "https://github.com/iotaledger/iota_common.git", 11 | ) 12 | 13 | git_repository( 14 | name = "org_iota_client", 15 | commit = "1c3d24682673f379c51762596ac1e810c1fdd394", 16 | remote = "https://github.com/iotaledger/iota.c.git", 17 | ) 18 | 19 | git_repository( 20 | name = "rules_iota", 21 | commit = "e08b0038f376d6c82b80f5283bb0a86648bb58dc", 22 | remote = "https://github.com/iotaledger/rules_iota.git", 23 | ) 24 | 25 | git_repository( 26 | name = "iota_toolchains", 27 | commit = "700904f445d15ef948d112bf0bccf7dd3814ae5c", 28 | remote = "https://github.com/iotaledger/toolchains.git", 29 | ) 30 | 31 | load("@rules_iota//:defs.bzl", "iota_deps") 32 | 33 | iota_deps() 34 | 35 | load("@iota_toolchains//:toolchains.bzl", "setup_initial_deps") 36 | 37 | setup_initial_deps() 38 | 39 | load("@iota_toolchains//:defs.bzl", "setup_toolchains_repositories") 40 | 41 | setup_toolchains_repositories() 42 | -------------------------------------------------------------------------------- /mam/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//visibility:public"]) 2 | 3 | load("@iota_toolchains//tools/emscripten:defs.bzl", "emcc_binary") 4 | 5 | cc_library( 6 | name = "defs", 7 | hdrs = ["defs.h"], 8 | ) 9 | 10 | # Build command: 11 | # bazel clean (recommended) 12 | # bazel build --spawn_strategy=local --define=workspace=$(bazel info workspace) --define=output_base=$(bazel info output_base) --config=emscripten //mam:mam.js 13 | 14 | #Uncomment the following rule when you want to build it explicitly 15 | 16 | #emcc_binary( 17 | # name = "mam.js", 18 | # deps = [ 19 | # "//mam/api", 20 | # ], 21 | #) 22 | 23 | cc_binary( 24 | name = "libmam.so", 25 | linkshared = True, 26 | deps = ["//mam/api"], 27 | ) 28 | -------------------------------------------------------------------------------- /mam/api/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//visibility:public"]) 2 | 3 | load("@org_iota_common//utils/containers:map_generator.bzl", "map_generate") 4 | 5 | cc_library( 6 | name = "api", 7 | srcs = ["api.c"], 8 | hdrs = ["api.h"], 9 | deps = [ 10 | ":trit_t_to_mam_msg_read_context_t_map", 11 | ":trit_t_to_mam_msg_write_context_t_map", 12 | "//mam/mam:message", 13 | "@org_iota_common//common:errors", 14 | "@org_iota_common//common/model:bundle", 15 | "@org_iota_common//utils:time", 16 | ], 17 | ) 18 | 19 | map_generate( 20 | additional_deps = ["//mam/mam:message"], 21 | additional_include_path = "mam/mam/message.h", 22 | key_type = "trit_t", 23 | parent_directory = "mam/api", 24 | value_type = "mam_msg_write_context_t", 25 | ) 26 | 27 | map_generate( 28 | additional_deps = ["//mam/mam:message"], 29 | additional_include_path = "mam/mam/message.h", 30 | key_type = "trit_t", 31 | parent_directory = "mam/api", 32 | value_type = "mam_msg_read_context_t", 33 | ) 34 | -------------------------------------------------------------------------------- /mam/api/tests/BUILD: -------------------------------------------------------------------------------- 1 | cc_test( 2 | name = "test_api", 3 | timeout = "eternal", 4 | srcs = ["test_api.c"], 5 | deps = [ 6 | "//mam/api", 7 | "//mam/mam/tests:test_channel_utils", 8 | "@org_iota_common//common/trinary:tryte_ascii", 9 | "@unity", 10 | ], 11 | ) 12 | -------------------------------------------------------------------------------- /mam/defs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https://github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by 6 | * [ITSec Lab] 7 | * 8 | * Refer to the LICENSE file for licensing information 9 | */ 10 | 11 | /** 12 | * @ingroup mam 13 | * 14 | * @{ 15 | * 16 | * @file 17 | * @brief 18 | * 19 | */ 20 | #ifndef __MAM_DEFS_H__ 21 | #define __MAM_DEFS_H__ 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #if defined __EMSCRIPTEN__ 28 | #include 29 | #define MAM_EXPORT EMSCRIPTEN_KEEPALIVE 30 | #else 31 | #define MAM_EXPORT 32 | #endif 33 | 34 | #ifdef __cplusplus 35 | extern "C" { 36 | #endif 37 | 38 | #include 39 | 40 | /*! `M = 3^n`, `m = 3^k`, `n>k`. t \in [-(M-1)/2 .. (M-1)/2]. */ 41 | #define MAM_MODS(t, M, m) ((((t) + ((M - 1) / 2)) % (m)) - ((m - 1) / 2)) 42 | #define MAM_DIVS(t, M, m) ((((t) + ((M - 1) / 2)) / (m)) - ((M / m - 1) / 2)) 43 | 44 | /*! \brief Signed integer type capable of storing single trit 45 | with values in range [-1,0,1]. */ 46 | typedef int8_t trint1_t; 47 | #define MAM_TRINT1_MAX ((trint1_t)1) 48 | #define MAM_TRINT1_MIN (-MAM_TRINT1_MAX) 49 | typedef trint1_t trit_t; 50 | 51 | #define MAM_ASSERT_TRINT1(t1) MAM_ASSERT(((t1) == (trint1_t)-1) || ((t1) == (trint1_t)0) || ((t1) == (trint1_t)1)) 52 | 53 | /*! \brief Return `x + s (mods 3)`. */ 54 | trit_t trit_add(trit_t x, trit_t s); 55 | 56 | /*! \brief Return `y - s (mods 3)`. */ 57 | trit_t trit_sub(trit_t y, trit_t s); 58 | 59 | /*! \brief Signed integer type capable of storing 3 trits 60 | with values in range [-13,..,-1,0,1,..,13]. */ 61 | typedef int8_t trint3_t; 62 | #define MAM_TRINT3_MAX ((trint3_t)13) 63 | #define MAM_TRINT3_MIN (-MAM_TRINT3_MAX) 64 | typedef trint3_t tryte_t; 65 | 66 | tryte_t tryte_from_trits(trit_t t0, trit_t t1, trit_t t2); 67 | 68 | char tryte_to_char(tryte_t t); 69 | 70 | bool tryte_from_char(tryte_t *t, char c); 71 | 72 | /*! \brief Signed integer type capable of storing 6 trits 73 | with values in range [-(3^6-1)/2=-364,..,-1,0,1,..,364=(3^6-1)/2]. */ 74 | typedef int16_t trint6_t; 75 | #define MAM_TRINT6_MAX ((trint6_t)364) 76 | #define MAM_TRINT6_MIN (-MAM_TRINT6_MAX) 77 | 78 | /*! \brief Signed integer type capable of storing 9 trits 79 | with values in range [-(3^9-1)/2=-9841,..,-1,0,1,..,9841=(3^9-1)/2]. */ 80 | typedef int16_t trint9_t; 81 | #define MAM_TRINT9_MAX ((trint9_t)9841) 82 | #define MAM_TRINT9_MIN (-MAM_TRINT9_MAX) 83 | 84 | /*! \brief Signed integer type capable of storing 18 trits 85 | with values in range [-(3^18-1)/2,..,-1,0,1,..,(3^18-1)/2]. */ 86 | typedef int32_t trint18_t; 87 | #define MAM_TRINT18_MAX ((trint18_t)193710244) 88 | #define MAM_TRINT18_MIN (-MAM_TRINT18_MAX) 89 | 90 | /*! \note `trintX_t` types represent integer values whereas 91 | `word_t` type represents fixed-size set of trits. */ 92 | 93 | /*! Unsigned 8-bit type. */ 94 | typedef uint8_t byte; 95 | 96 | /*! \brief Assert expression. */ 97 | #define MAM_ASSERT(expr) assert(expr) 98 | 99 | #ifdef __cplusplus 100 | } 101 | #endif 102 | 103 | #endif // __MAM_DEFS_H__ 104 | 105 | /** @} */ 106 | -------------------------------------------------------------------------------- /mam/doxy.txt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 IOTA Stiftung 3 | * https://github.com/iotaledger/entangled 4 | * 5 | * Refer to the LICENSE file for licensing information 6 | */ 7 | 8 | /** 9 | * @defgroup mam MAM 10 | * @brief The Masked Authenticated Messaging (MAM) implementation. 11 | * 12 | * TODO 13 | */ 14 | -------------------------------------------------------------------------------- /mam/examples/BUILD: -------------------------------------------------------------------------------- 1 | cc_binary( 2 | name = "send-header", 3 | srcs = ["send-header.c"], 4 | deps = [ 5 | ":send-common", 6 | ], 7 | ) 8 | 9 | cc_binary( 10 | name = "send-packet", 11 | srcs = ["send-packet.c"], 12 | deps = [ 13 | ":send-common", 14 | ], 15 | ) 16 | 17 | cc_binary( 18 | name = "send-msg", 19 | srcs = ["send-msg.c"], 20 | deps = [ 21 | ":send-common", 22 | ], 23 | ) 24 | 25 | cc_library( 26 | name = "send-common", 27 | srcs = ["send-common.c"], 28 | hdrs = ["send-common.h"], 29 | deps = [ 30 | ":common", 31 | ], 32 | ) 33 | 34 | cc_binary( 35 | name = "recv", 36 | srcs = ["recv.c"], 37 | deps = [ 38 | ":common", 39 | ], 40 | ) 41 | 42 | cc_library( 43 | name = "common", 44 | srcs = ["common.c"], 45 | hdrs = ["common.h"], 46 | deps = [ 47 | "//mam/api", 48 | "@org_iota_client//cclient/api", 49 | "@org_iota_common//common/trinary:trit_tryte", 50 | "@org_iota_common//common/trinary:tryte_ascii", 51 | ], 52 | ) 53 | 54 | cc_binary( 55 | name = "ntru-key-exchange", 56 | srcs = ["ntru-key-exchange.c"], 57 | deps = [ 58 | "//mam/api", 59 | ], 60 | ) 61 | -------------------------------------------------------------------------------- /mam/examples/README.md: -------------------------------------------------------------------------------- 1 | **PLEASE CREATE A NEW SEED WHILE TRYING THESE EXAMPLES** 2 | 3 | # Examples 4 | 5 | These examples only serve the purpose of demonstrating the core features of MAM and are not as flexible as the library permits. 6 | 7 | They will allow you to send and receive payloads from bundles. 8 | 9 | Listening for new bundles is out of the scope of these examples. 10 | 11 | For the proper execution of the examples, a file will be created under `/tmp/mam.bin`. 12 | 13 | This file will be bound to a seed. If you wish to change seed, delete the file. 14 | 15 | ## Disclaimer 16 | 17 | MAM is still under development, undefined behaviour can arise. 18 | 19 | If so, please file an issue: https://github.com/iotaledger/entangled/issues/new. 20 | 21 | **DO NOT USE YOUR USUAL TOKENS SEED** 22 | 23 | ## Running 24 | 25 | 26 | ### Sending 27 | 28 | This command will send a header meaning it will declare a new message. 29 | 30 | `bazel run -c opt -- //mam/examples:send-header ` 31 | 32 | This command will send a packet to an already existing message. 33 | 34 | `bazel run -c opt -- //mam/examples:send-packet ` 35 | 36 | This command will send a header and a packet at the same time. 37 | 38 | `bazel run -c opt -- //mam/examples:send-msg ` 39 | 40 | ### Receiving 41 | 42 | `bazel run -c opt -- //mam/examples:recv (optional)` 43 | -------------------------------------------------------------------------------- /mam/examples/common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https:github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by 6 | * [ITSec Lab] 7 | * 8 | * Refer to the LICENSE file for licensing information 9 | */ 10 | 11 | #ifndef __MAM_EXAMPLES_COMMON_H__ 12 | #define __MAM_EXAMPLES_COMMON_H__ 13 | 14 | #include "cclient/api/core/core_api.h" 15 | #include "cclient/api/extended/extended_api.h" 16 | #include "common/trinary/trit_tryte.h" 17 | #include "common/trinary/tryte_ascii.h" 18 | #include "mam/api/api.h" 19 | 20 | #define DUMMY_SEED \ 21 | "DUMMYSEEDDUMMYSEEDDUMMYSEEDDUMMYSEEDDUMMYSEEDDUMMYSEEDDUMMYSEEDDUMMYSEED99" \ 22 | "9999999" 23 | #define TEST_CHANNEL_NAME "CHANAME" 24 | #define TEST_MSS_DEPTH 1 25 | #define MAM_FILE "/tmp/mam.bin" 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | find_transactions_req_t recv_example_req; 32 | 33 | extern mam_psk_t const psk; 34 | 35 | retcode_t mam_example_channel_create(mam_api_t *const api, tryte_t *const channel_id); 36 | 37 | retcode_t send_bundle(char const *const host, uint16_t const port, bundle_transactions_t *const bundle); 38 | retcode_t receive_bundle(char const *const host, uint16_t const port, tryte_t const *const bundle_hash, 39 | bundle_transactions_t *const bundle); 40 | 41 | #ifdef __cplusplus 42 | } 43 | #endif 44 | 45 | #endif // __MAM_EXAMPLES_COMMON_H__ 46 | -------------------------------------------------------------------------------- /mam/examples/ntru-key-exchange.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 IOTA Stiftung 3 | * https:github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by 6 | * [ITSec Lab] 7 | * 8 | * Refer to the LICENSE file for licensing information 9 | */ 10 | 11 | #include 12 | #include "mam/api/api.h" 13 | #include "mam/ntru/ntru.h" 14 | 15 | #define SENDERSEED "SENDERSEED9SENDERSEED9SENDERSEED9SENDERSEED9SENDERSEED9SENDERSEED9SENDERSEED99999" 16 | #define RECEIVERSEED "RECEIVERSEED9RECEIVERSEED9RECEIVERSEED9RECEIVERSEED9RECEIVERSEED9RECEIVERSEED9999" 17 | #define NONCE "ABCDEFGHI" 18 | #define PL "PAYLOADTEST" 19 | 20 | int main() { 21 | retcode_t ret = RC_OK; 22 | // Setting up two APIs 23 | mam_api_t sender_api; 24 | tryte_t *sender_seed = (tryte_t *)SENDERSEED; 25 | ERR_BIND_RETURN(mam_api_init(&sender_api, sender_seed), ret); 26 | mam_api_t receiver_api; 27 | tryte_t *receiver_seed = (tryte_t *)RECEIVERSEED; 28 | ERR_BIND_RETURN(mam_api_init(&receiver_api, receiver_seed), ret); 29 | // Generating a keypair for the receiver api 30 | mam_ntru_sk_t ntru; 31 | MAM_TRITS_DEF(nonce, 3 * 9); 32 | nonce = MAM_TRITS_INIT(nonce, 3 * 9); 33 | trits_from_str(nonce, NONCE); 34 | ntru_sk_reset(&ntru); 35 | ntru_sk_gen(&ntru, &receiver_api.prng, nonce); 36 | // Setting the generated keypair to the receiver API 37 | ERR_BIND_RETURN(mam_api_add_ntru_sk(&receiver_api, &ntru), ret); 38 | // Adding the receiver APIs public key to the sender API public key list 39 | ERR_BIND_RETURN(mam_api_add_ntru_pk(&sender_api, &ntru.public_key), ret); 40 | // Preparing channel and endpoint with sender API with randomly chosen height 41 | tryte_t channel_id[MAM_CHANNEL_ID_TRYTE_SIZE]; 42 | ERR_BIND_RETURN(mam_api_channel_create(&sender_api, 2, channel_id), ret); 43 | tryte_t endpoint_id[MAM_ENDPOINT_ID_TRYTE_SIZE]; 44 | ERR_BIND_RETURN(mam_api_endpoint_create(&sender_api, 2, channel_id, endpoint_id), ret); 45 | // prepare bundle for sender API to write to 46 | bundle_transactions_t *bundle = NULL; 47 | bundle_transactions_new(&bundle); 48 | // prepare and write header and packet 49 | trit_t message_id[MAM_MSG_ID_SIZE]; 50 | ERR_BIND_RETURN(mam_api_bundle_write_header_on_endpoint(&sender_api, channel_id, endpoint_id, NULL, 51 | sender_api.ntru_pks, bundle, message_id), 52 | ret); 53 | ERR_BIND_RETURN(mam_api_bundle_write_packet(&sender_api, message_id, (tryte_t *)PL, strlen(PL), MAM_MSG_CHECKSUM_SIG, 54 | true, bundle), 55 | ret); 56 | // Set created channel and endpoint as trusted in receiver API 57 | ERR_BIND_RETURN(mam_api_add_trusted_channel_pk(&receiver_api, channel_id), ret); 58 | ERR_BIND_RETURN(mam_api_add_trusted_endpoint_pk(&receiver_api, endpoint_id), ret); 59 | // read the bundle with the receiver API and print the decrypted payload 60 | tryte_t *payload = NULL; 61 | size_t payload_size = 0; 62 | bool is_last_packet = false; 63 | ERR_BIND_RETURN(mam_api_bundle_read(&receiver_api, bundle, &payload, &payload_size, &is_last_packet), ret); 64 | fprintf(stderr, "Payload: "); 65 | for (size_t i = 0; i < payload_size; i++) { 66 | fprintf(stderr, "%c", payload[i]); 67 | } 68 | fprintf(stderr, "\n"); 69 | // free ressources 70 | free(payload); 71 | bundle_transactions_free(&bundle); 72 | mam_api_destroy(&sender_api); 73 | mam_api_destroy(&receiver_api); 74 | // finished 75 | return ret; 76 | } 77 | -------------------------------------------------------------------------------- /mam/examples/recv.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https:github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by 6 | * [ITSec Lab] 7 | * 8 | * Refer to the LICENSE file for licensing information 9 | */ 10 | 11 | #include 12 | 13 | #include "mam/examples/common.h" 14 | 15 | int main(int ac, char **av) { 16 | mam_api_t api; 17 | int ret = EXIT_SUCCESS; 18 | tryte_t *payload_trytes = NULL; 19 | size_t payload_size = 0; 20 | bundle_transactions_t *bundle = NULL; 21 | bundle_transactions_new(&bundle); 22 | bool is_last_packet; 23 | 24 | if (ac < 4 || ac > 5) { 25 | fprintf(stderr, "usage: recv (optional)\n"); 26 | return EXIT_FAILURE; 27 | } 28 | 29 | // Loading or creating MAM API 30 | if ((ret = mam_api_load(MAM_FILE, &api, NULL, 0)) == RC_UTILS_FAILED_TO_OPEN_FILE) { 31 | if ((ret = mam_api_init(&api, (tryte_t *)av[3])) != RC_OK) { 32 | fprintf(stderr, "mam_api_init failed with err %d\n", ret); 33 | return EXIT_FAILURE; 34 | } 35 | } else if (ret != RC_OK) { 36 | fprintf(stderr, "mam_api_load failed with err %d\n", ret); 37 | return EXIT_FAILURE; 38 | } 39 | 40 | if (receive_bundle(av[1], atoi(av[2]), (tryte_t *)av[3], bundle) != RC_OK) { 41 | return EXIT_FAILURE; 42 | } 43 | 44 | mam_psk_t_set_add(&api.psks, &psk); 45 | if (ac == 5) { 46 | mam_api_add_trusted_channel_pk(&api, (tryte_t *)av[4]); 47 | } 48 | 49 | if (mam_api_bundle_read(&api, bundle, &payload_trytes, &payload_size, &is_last_packet) == RC_OK) { 50 | if (payload_trytes == NULL || payload_size == 0) { 51 | fprintf(stderr, "No payload\n"); 52 | } else { 53 | char *payload = calloc(payload_size * 2 + 1, sizeof(char)); 54 | 55 | trytes_to_ascii(payload_trytes, payload_size, payload); 56 | fprintf(stderr, "Payload: %s\n", payload); 57 | free(payload); 58 | } 59 | } else { 60 | fprintf(stderr, "mam_api_bundle_read_msg failed\n"); 61 | } 62 | 63 | // Saving and destroying MAM API 64 | if ((ret = mam_api_save(&api, MAM_FILE, NULL, 0)) != RC_OK) { 65 | fprintf(stderr, "mam_api_save failed with err %d\n", ret); 66 | } 67 | if ((ret = mam_api_destroy(&api)) != RC_OK) { 68 | fprintf(stderr, "mam_api_destroy failed with err %d\n", ret); 69 | return EXIT_FAILURE; 70 | } 71 | 72 | // Cleanup 73 | { bundle_transactions_free(&bundle); } 74 | 75 | return ret; 76 | } 77 | -------------------------------------------------------------------------------- /mam/examples/send-common.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https:github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by 6 | * [ITSec Lab] 7 | * 8 | * Refer to the LICENSE file for licensing information 9 | */ 10 | 11 | #include 12 | 13 | #include "mam/examples/send-common.h" 14 | 15 | retcode_t mam_example_announce_channel(mam_api_t* const api, tryte_t const* const channel_id, 16 | bundle_transactions_t* const bundle, trit_t* const msg_id, 17 | tryte_t* const new_channel_id) { 18 | retcode_t ret = RC_OK; 19 | tryte_t msg_id_trytes[MAM_MSG_ID_SIZE / NUMBER_OF_TRITS_IN_A_TRYTE]; 20 | mam_psk_t_set_t psks = NULL; 21 | 22 | if (!mam_psk_t_set_contains(psks, &psk)) { 23 | if ((ret = mam_psk_t_set_add(&psks, &psk)) != RC_OK) { 24 | return ret; 25 | } 26 | } 27 | 28 | ERR_BIND_RETURN(mam_api_channel_create(api, MAM_EXAMPLES_MSS_HEIGHT, new_channel_id), ret); 29 | 30 | if ((ret = mam_api_bundle_announce_channel(api, channel_id, new_channel_id, psks, NULL, bundle, msg_id)) != RC_OK) { 31 | return ret; 32 | } 33 | mam_psk_t_set_free(&psks); 34 | 35 | trits_to_trytes(msg_id, msg_id_trytes, MAM_MSG_ID_SIZE); 36 | fprintf(stderr, "Message ID: "); 37 | for (size_t i = 0; i < MAM_MSG_ID_SIZE / 3; i++) { 38 | fprintf(stderr, "%c", msg_id_trytes[i]); 39 | } 40 | fprintf(stderr, "\n"); 41 | 42 | fprintf(stderr, "CH1 ID: "); 43 | for (size_t i = 0; i < MAM_CHANNEL_ID_TRYTE_SIZE; i++) { 44 | fprintf(stderr, "%c", new_channel_id[i]); 45 | } 46 | fprintf(stderr, "\n"); 47 | 48 | return ret; 49 | } 50 | 51 | retcode_t mam_example_announce_endpoint(mam_api_t* const api, tryte_t const* const channel_id, 52 | bundle_transactions_t* const bundle, trit_t* const msg_id, 53 | tryte_t* const new_endpoint_id) { 54 | retcode_t ret = RC_OK; 55 | tryte_t msg_id_trytes[MAM_MSG_ID_SIZE / NUMBER_OF_TRITS_IN_A_TRYTE]; 56 | mam_psk_t_set_t psks = NULL; 57 | 58 | if (!mam_psk_t_set_contains(psks, &psk)) { 59 | if ((ret = mam_psk_t_set_add(&psks, &psk)) != RC_OK) { 60 | return ret; 61 | } 62 | } 63 | 64 | ERR_BIND_RETURN(mam_api_endpoint_create(api, MAM_EXAMPLES_MSS_HEIGHT, channel_id, new_endpoint_id), ret); 65 | 66 | if ((ret = mam_api_bundle_announce_endpoint(api, channel_id, new_endpoint_id, psks, NULL, bundle, msg_id)) != RC_OK) { 67 | return ret; 68 | } 69 | mam_psk_t_set_free(&psks); 70 | 71 | trits_to_trytes(msg_id, msg_id_trytes, MAM_MSG_ID_SIZE); 72 | fprintf(stderr, "Message ID: "); 73 | for (size_t i = 0; i < MAM_MSG_ID_SIZE / 3; i++) { 74 | fprintf(stderr, "%c", msg_id_trytes[i]); 75 | } 76 | fprintf(stderr, "\n"); 77 | 78 | fprintf(stderr, "EP1 ID: "); 79 | for (size_t i = 0; i < MAM_ENDPOINT_ID_TRYTE_SIZE; i++) { 80 | fprintf(stderr, "%c", new_endpoint_id[i]); 81 | } 82 | fprintf(stderr, "\n"); 83 | 84 | return ret; 85 | } 86 | 87 | retcode_t mam_example_write_header_on_channel(mam_api_t* const api, tryte_t const* const channel_id, 88 | bundle_transactions_t* const bundle, trit_t* const msg_id) { 89 | retcode_t ret = RC_OK; 90 | tryte_t msg_id_trytes[MAM_MSG_ID_SIZE / 3]; 91 | mam_psk_t_set_t psks = NULL; 92 | 93 | if (!mam_psk_t_set_contains(psks, &psk)) { 94 | if ((ret = mam_psk_t_set_add(&psks, &psk)) != RC_OK) { 95 | return ret; 96 | } 97 | } 98 | 99 | if ((ret = mam_api_bundle_write_header_on_channel(api, channel_id, psks, NULL, bundle, msg_id)) != RC_OK) { 100 | return ret; 101 | } 102 | mam_psk_t_set_free(&psks); 103 | 104 | trits_to_trytes(msg_id, msg_id_trytes, MAM_MSG_ID_SIZE); 105 | fprintf(stderr, "Message ID: "); 106 | for (size_t i = 0; i < MAM_MSG_ID_SIZE / 3; i++) { 107 | fprintf(stderr, "%c", msg_id_trytes[i]); 108 | } 109 | fprintf(stderr, "\n"); 110 | 111 | return ret; 112 | } 113 | 114 | retcode_t mam_example_write_header_on_endpoint(mam_api_t* const api, tryte_t const* const channel_id, 115 | tryte_t const* const endpoint_id, bundle_transactions_t* const bundle, 116 | trit_t* const msg_id) { 117 | retcode_t ret = RC_OK; 118 | tryte_t msg_id_trytes[MAM_MSG_ID_SIZE / 3]; 119 | mam_psk_t_set_t psks = NULL; 120 | 121 | if (!mam_psk_t_set_contains(psks, &psk)) { 122 | if ((ret = mam_psk_t_set_add(&psks, &psk)) != RC_OK) { 123 | return ret; 124 | } 125 | } 126 | 127 | if ((ret = mam_api_bundle_write_header_on_endpoint(api, channel_id, endpoint_id, psks, NULL, bundle, msg_id)) != 128 | RC_OK) { 129 | return ret; 130 | } 131 | 132 | mam_psk_t_set_free(&psks); 133 | 134 | trits_to_trytes(msg_id, msg_id_trytes, MAM_MSG_ID_SIZE); 135 | fprintf(stderr, "Message ID: "); 136 | for (size_t i = 0; i < MAM_MSG_ID_SIZE / 3; i++) { 137 | fprintf(stderr, "%c", msg_id_trytes[i]); 138 | } 139 | fprintf(stderr, "\n"); 140 | 141 | return ret; 142 | } 143 | 144 | retcode_t mam_example_write_packet(mam_api_t* const api, bundle_transactions_t* const bundle, char const* const payload, 145 | trit_t const* const msg_id, bool is_last_packet) { 146 | retcode_t ret = RC_OK; 147 | tryte_t* payload_trytes = (tryte_t*)malloc(2 * strlen(payload) * sizeof(tryte_t)); 148 | 149 | ascii_to_trytes(payload, payload_trytes); 150 | if ((ret = mam_api_bundle_write_packet(api, msg_id, payload_trytes, strlen(payload) * 2, 0, is_last_packet, 151 | bundle)) != RC_OK) { 152 | return ret; 153 | } 154 | free(payload_trytes); 155 | 156 | return ret; 157 | } 158 | -------------------------------------------------------------------------------- /mam/examples/send-common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https:github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by 6 | * [ITSec Lab] 7 | * 8 | * Refer to the LICENSE file for licensing information 9 | */ 10 | 11 | #ifndef __MAM_EXAMPLES_SEND_COMMON_H__ 12 | #define __MAM_EXAMPLES_SEND_COMMON_H__ 13 | 14 | #include "mam/examples/common.h" 15 | 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #endif 19 | 20 | #define MAM_EXAMPLES_MSS_HEIGHT 3 21 | 22 | /** 23 | * Creates and announce a channel (Header only) 24 | * 25 | * @param api - The API [in,out] 26 | * @param channel_id - A known channel ID [in] 27 | * @param bundle - The bundle that the packet will be written into [out] 28 | * @param msg_id - The msg_id 29 | * @param new_channel_id - The new channel ID 30 | * 31 | * @return return code 32 | */ 33 | retcode_t mam_example_announce_channel(mam_api_t* const api, tryte_t const* const channel_id, 34 | bundle_transactions_t* const bundle, trit_t* const msg_id, 35 | tryte_t* const new_channel_id); 36 | 37 | /** 38 | * Creates and announce a endpoint (Header only) 39 | * 40 | * @param api - The API [in,out] 41 | * @param channel_id - A known channel ID [in] 42 | * @param bundle - The bundle that the packet will be written into [out] 43 | * @param msg_id - The msg_id 44 | * @param new_endpoint - The new endpoint 45 | * 46 | * @return return code 47 | */ 48 | retcode_t mam_example_announce_endpoint(mam_api_t* const api, tryte_t const* const channel_id, 49 | bundle_transactions_t* const bundle, trit_t* const msg_id, 50 | tryte_t* const new_endpoint_id); 51 | 52 | /** 53 | * Writes a header only bundle on a channel 54 | * 55 | * @param api - The API [in,out] 56 | * @param channel_id - A known channel ID [in] 57 | * @param bundle - The bundle that the packet will be written into [out] 58 | * @param msg_id - The msg_id 59 | * 60 | * @return return code 61 | */ 62 | retcode_t mam_example_write_header_on_channel(mam_api_t* const api, tryte_t const* const channel_id, 63 | bundle_transactions_t* const bundle, trit_t* const msg_id); 64 | 65 | /** 66 | * Writes a header only bundle on an endpoint 67 | * 68 | * @param api - The API [in,out] 69 | * @param channel_id - A known channel ID [in] 70 | * @param endpoint_id - A known endpoint ID [in] 71 | * @param bundle - The bundle that the packet will be written into [out] 72 | * @param msg_id - The msg_id 73 | * 74 | * @return return code 75 | */ 76 | retcode_t mam_example_write_header_on_endpoint(mam_api_t* const api, tryte_t const* const channel_id, 77 | tryte_t const* const endpoint_id, bundle_transactions_t* const bundle, 78 | trit_t* const msg_id); 79 | 80 | /** 81 | * Writes a packet on a bundle 82 | * 83 | * @param api - The API [in,out] 84 | * @param bundle - The bundle that the packet will be written into [out] 85 | * @param payload - The payload to write [in] 86 | * @param msg_id - The msg_id [in] 87 | * @param is_last_packet - True if this is the last packet to be written 88 | * 89 | * @return return code 90 | */ 91 | retcode_t mam_example_write_packet(mam_api_t* const api, bundle_transactions_t* const bundle, char const* const payload, 92 | trit_t const* const msg_id, bool is_last_packet); 93 | 94 | #ifdef __cplusplus 95 | } 96 | #endif 97 | 98 | #endif // __MAM_EXAMPLES_SEND_COMMON_H__ 99 | -------------------------------------------------------------------------------- /mam/examples/send-header.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https:github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by 6 | * [ITSec Lab] 7 | * 8 | * Refer to the LICENSE file for licensing information 9 | */ 10 | 11 | #include 12 | 13 | #include "mam/examples/send-common.h" 14 | 15 | int main(int ac, char **av) { 16 | mam_api_t api; 17 | bundle_transactions_t *bundle = NULL; 18 | tryte_t channel_id[MAM_CHANNEL_ID_TRYTE_SIZE]; 19 | mam_msg_pubkey_t msg_pubkey; 20 | int msg_pubkey_int; 21 | retcode_t ret = RC_OK; 22 | 23 | if (ac != 5) { 24 | fprintf(stderr, 25 | "usage: send-header (0 " 26 | "- on channel, 1 - on endpoint, 2 - announce channel, 3 - " 27 | "announce endpoint)\n"); 28 | return EXIT_FAILURE; 29 | } 30 | 31 | // Loading or creating MAM API 32 | if ((ret = mam_api_load(MAM_FILE, &api, NULL, 0)) == RC_UTILS_FAILED_TO_OPEN_FILE) { 33 | if ((ret = mam_api_init(&api, (tryte_t *)av[3])) != RC_OK) { 34 | fprintf(stderr, "mam_api_init failed with err %d\n", ret); 35 | return EXIT_FAILURE; 36 | } 37 | } else if (ret != RC_OK) { 38 | fprintf(stderr, "mam_api_load failed with err %d\n", ret); 39 | return EXIT_FAILURE; 40 | } 41 | 42 | msg_pubkey_int = atoi(av[4]); 43 | if (msg_pubkey_int < 0 || msg_pubkey_int > 3) { 44 | fprintf(stderr, 45 | "usage: send-header (0 " 46 | "- on channel, 1 - on endpoint, 2 - announce channel, 3 - " 47 | "announce endpoint)\n"); 48 | return EXIT_FAILURE; 49 | } 50 | 51 | msg_pubkey = (mam_msg_pubkey_t)msg_pubkey_int; 52 | 53 | // Creating channel 54 | if ((ret = mam_example_channel_create(&api, channel_id)) != RC_OK) { 55 | fprintf(stderr, "mam_example_channel_create failed with err %d\n", ret); 56 | return EXIT_FAILURE; 57 | } 58 | 59 | bundle_transactions_new(&bundle); 60 | 61 | { 62 | // Writing header to bundle 63 | trit_t msg_id[MAM_MSG_ID_SIZE]; 64 | 65 | if (msg_pubkey == MAM_MSG_PUBKEY_CHID) { 66 | if ((ret = mam_example_write_header_on_channel(&api, channel_id, bundle, msg_id)) != RC_OK) { 67 | fprintf(stderr, "mam_example_write_header failed with err %d\n", ret); 68 | return EXIT_FAILURE; 69 | } 70 | } else if (msg_pubkey == MAM_MSG_PUBKEY_EPID) { 71 | tryte_t new_endpoint_id[MAM_ENDPOINT_ID_TRYTE_SIZE]; 72 | 73 | if ((ret = mam_example_announce_endpoint(&api, channel_id, bundle, msg_id, new_endpoint_id)) != RC_OK) { 74 | fprintf(stderr, "mam_example_announce_endpoint failed with err %d\n", ret); 75 | return EXIT_FAILURE; 76 | } 77 | // Sending bundle 78 | if ((ret = send_bundle(av[1], atoi(av[2]), bundle)) != RC_OK) { 79 | fprintf(stderr, "send_bundle failed with err %d\n", ret); 80 | return EXIT_FAILURE; 81 | } 82 | 83 | bundle_transactions_clear(bundle); 84 | if ((ret = mam_example_write_header_on_endpoint(&api, channel_id, new_endpoint_id, bundle, msg_id)) != RC_OK) { 85 | fprintf(stderr, "mam_example_write_header_on_endpoint failed with err %d\n", ret); 86 | return EXIT_FAILURE; 87 | } 88 | return 0; 89 | } else if (msg_pubkey == MAM_MSG_PUBKEY_EPID1) { 90 | tryte_t new_endpoint_id[MAM_ENDPOINT_ID_TRYTE_SIZE]; 91 | 92 | bundle_transactions_clear(bundle); 93 | if ((ret = mam_example_announce_endpoint(&api, channel_id, bundle, msg_id, new_endpoint_id)) != RC_OK) { 94 | fprintf(stderr, "mam_example_announce_endpoint failed with err %d\n", ret); 95 | return EXIT_FAILURE; 96 | } 97 | } else if (msg_pubkey == MAM_MSG_PUBKEY_CHID1) { 98 | tryte_t new_channel_id[MAM_CHANNEL_ID_TRYTE_SIZE]; 99 | 100 | if ((ret = mam_example_announce_channel(&api, channel_id, bundle, msg_id, new_channel_id)) != RC_OK) { 101 | fprintf(stderr, "mam_example_announce_endpoint failed with err %d\n", ret); 102 | return EXIT_FAILURE; 103 | } 104 | // Sending bundle 105 | if ((ret = send_bundle(av[1], atoi(av[2]), bundle)) != RC_OK) { 106 | fprintf(stderr, "send_bundle failed with err %d\n", ret); 107 | return EXIT_FAILURE; 108 | } 109 | 110 | bundle_transactions_clear(bundle); 111 | if ((ret = mam_example_write_header_on_channel(&api, new_channel_id, bundle, msg_id)) != RC_OK) { 112 | fprintf(stderr, "mam_example_write_header failed with err %d\n", ret); 113 | return EXIT_FAILURE; 114 | } 115 | } 116 | } 117 | 118 | // Sending bundle 119 | if ((ret = send_bundle(av[1], atoi(av[2]), bundle)) != RC_OK) { 120 | fprintf(stderr, "send_bundle failed with err %d\n", ret); 121 | return EXIT_FAILURE; 122 | } 123 | 124 | // Saving and destroying MAM API 125 | if ((ret = mam_api_save(&api, MAM_FILE, NULL, 0)) != RC_OK) { 126 | fprintf(stderr, "mam_api_save failed with err %d\n", ret); 127 | } 128 | if ((ret = mam_api_destroy(&api)) != RC_OK) { 129 | fprintf(stderr, "mam_api_destroy failed with err %d\n", ret); 130 | return EXIT_FAILURE; 131 | } 132 | 133 | // Cleanup 134 | { bundle_transactions_free(&bundle); } 135 | 136 | return EXIT_SUCCESS; 137 | } 138 | -------------------------------------------------------------------------------- /mam/examples/send-msg.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https:github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by 6 | * [ITSec Lab] 7 | * 8 | * Refer to the LICENSE file for licensing information 9 | */ 10 | 11 | #include 12 | 13 | #include "mam/examples/send-common.h" 14 | 15 | int main(int ac, char **av) { 16 | mam_api_t api; 17 | bundle_transactions_t *bundle = NULL; 18 | tryte_t channel_id[MAM_CHANNEL_ID_TRYTE_SIZE]; 19 | retcode_t ret = RC_OK; 20 | 21 | if (ac != 6) { 22 | fprintf(stderr, "usage: send-msg \n"); 23 | return EXIT_FAILURE; 24 | } 25 | 26 | if (strcmp(av[5], "yes") && strcmp(av[5], "no")) { 27 | fprintf(stderr, "Arg should be \"yes\" or \"no\" only\n"); 28 | return EXIT_FAILURE; 29 | } 30 | 31 | // Loading or creating MAM API 32 | if ((ret = mam_api_load(MAM_FILE, &api, NULL, 0)) == RC_UTILS_FAILED_TO_OPEN_FILE) { 33 | if ((ret = mam_api_init(&api, (tryte_t *)av[3])) != RC_OK) { 34 | fprintf(stderr, "mam_api_init failed with err %d\n", ret); 35 | return EXIT_FAILURE; 36 | } 37 | } else if (ret != RC_OK) { 38 | fprintf(stderr, "mam_api_load failed with err %d\n", ret); 39 | return EXIT_FAILURE; 40 | } 41 | 42 | // Creating channel 43 | if ((ret = mam_example_channel_create(&api, channel_id)) != RC_OK) { 44 | fprintf(stderr, "mam_example_channel_create failed with err %d\n", ret); 45 | return EXIT_FAILURE; 46 | } 47 | 48 | bundle_transactions_new(&bundle); 49 | 50 | { 51 | trit_t msg_id[MAM_MSG_ID_SIZE]; 52 | 53 | // Writing header to bundle 54 | if ((ret = mam_example_write_header_on_channel(&api, channel_id, bundle, msg_id)) != RC_OK) { 55 | fprintf(stderr, "mam_example_write_header failed with err %d\n", ret); 56 | return EXIT_FAILURE; 57 | } 58 | 59 | // Writing packet to bundle 60 | bool last_packet = strcmp(av[5], "yes") == 0; 61 | 62 | // if (mam_channel_num_remaining_sks(channel) == 0) { 63 | // TODO 64 | // - remove old ch 65 | // - create new ch 66 | // - add ch via `mam_api_add_channel` 67 | 68 | // return RC_OK; 69 | // } 70 | 71 | if ((ret = mam_example_write_packet(&api, bundle, av[4], msg_id, last_packet)) != RC_OK) { 72 | fprintf(stderr, "mam_example_write_packet failed with err %d\n", ret); 73 | return EXIT_FAILURE; 74 | } 75 | } 76 | 77 | // Sending bundle 78 | if ((ret = send_bundle(av[1], atoi(av[2]), bundle)) != RC_OK) { 79 | fprintf(stderr, "send_bundle failed with err %d\n", ret); 80 | return EXIT_FAILURE; 81 | } 82 | 83 | // Saving and destroying MAM API 84 | if ((ret = mam_api_save(&api, MAM_FILE, NULL, 0)) != RC_OK) { 85 | fprintf(stderr, "mam_api_save failed with err %d\n", ret); 86 | } 87 | if ((ret = mam_api_destroy(&api)) != RC_OK) { 88 | fprintf(stderr, "mam_api_destroy failed with err %d\n", ret); 89 | return EXIT_FAILURE; 90 | } 91 | 92 | // Cleanup 93 | { bundle_transactions_free(&bundle); } 94 | 95 | return EXIT_SUCCESS; 96 | } 97 | -------------------------------------------------------------------------------- /mam/examples/send-packet.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https:github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by 6 | * [ITSec Lab] 7 | * 8 | * Refer to the LICENSE file for licensing information 9 | */ 10 | 11 | #include 12 | 13 | #include "mam/examples/send-common.h" 14 | 15 | int main(int ac, char **av) { 16 | mam_api_t api; 17 | bundle_transactions_t *bundle = NULL; 18 | retcode_t ret = RC_OK; 19 | 20 | if (ac != 7) { 21 | fprintf(stderr, 22 | "usage: send-packet " 23 | "\n"); 24 | return EXIT_FAILURE; 25 | } 26 | 27 | if (strcmp(av[6], "yes") && strcmp(av[6], "no")) { 28 | fprintf(stderr, "Arg should be \"yes\" or \"no\" only\n"); 29 | return EXIT_FAILURE; 30 | } 31 | 32 | // Loading or creating MAM API 33 | if ((ret = mam_api_load(MAM_FILE, &api, NULL, 0)) == RC_UTILS_FAILED_TO_OPEN_FILE) { 34 | if ((ret = mam_api_init(&api, (tryte_t *)av[3])) != RC_OK) { 35 | fprintf(stderr, "mam_api_init failed with err %d\n", ret); 36 | return EXIT_FAILURE; 37 | } 38 | } else if (ret != RC_OK) { 39 | fprintf(stderr, "mam_api_load failed with err %d\n", ret); 40 | return EXIT_FAILURE; 41 | } 42 | 43 | bundle_transactions_new(&bundle); 44 | 45 | // Writing packet to bundle 46 | { 47 | trit_t msg_id[MAM_MSG_ID_SIZE]; 48 | 49 | bool last_packet = strcmp(av[6], "yes") == 0; 50 | trytes_to_trits((tryte_t *)av[4], msg_id, strlen(av[4])); 51 | if ((ret = mam_example_write_packet(&api, bundle, av[5], msg_id, last_packet)) != RC_OK) { 52 | fprintf(stderr, "mam_example_write_packet failed with err %d\n", ret); 53 | return EXIT_FAILURE; 54 | } 55 | } 56 | 57 | // Sending bundle 58 | if ((ret = send_bundle(av[1], atoi(av[2]), bundle)) != RC_OK) { 59 | fprintf(stderr, "send_bundle failed with err %d\n", ret); 60 | return EXIT_FAILURE; 61 | } 62 | 63 | // Saving and destroying MAM API 64 | if ((ret = mam_api_save(&api, MAM_FILE, NULL, 0)) != RC_OK) { 65 | fprintf(stderr, "mam_api_save failed with err %d\n", ret); 66 | } 67 | if ((ret = mam_api_destroy(&api)) != RC_OK) { 68 | fprintf(stderr, "mam_api_destroy failed with err %d\n", ret); 69 | return EXIT_FAILURE; 70 | } 71 | 72 | // Cleanup 73 | { bundle_transactions_free(&bundle); } 74 | 75 | return EXIT_SUCCESS; 76 | } 77 | -------------------------------------------------------------------------------- /mam/mam/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//visibility:public"]) 2 | 3 | load("@org_iota_common//utils/containers:typed_container_generator.bzl", "typed_container_generate") 4 | 5 | cc_library( 6 | name = "message", 7 | srcs = ["message.c"], 8 | hdrs = ["message.h"], 9 | deps = [ 10 | ":channel", 11 | ":endpoint", 12 | ":mam_pk_t_set", 13 | "//mam:defs", 14 | "//mam/mss", 15 | "//mam/ntru", 16 | "//mam/pb3", 17 | "//mam/prng", 18 | "//mam/psk", 19 | "//mam/sponge:spongos_types", 20 | ], 21 | ) 22 | 23 | cc_library( 24 | name = "channel_hdr", 25 | hdrs = ["channel.h"], 26 | deps = [ 27 | ":mam_endpoint_t_set", 28 | "//mam/mss", 29 | "//mam/trits", 30 | ], 31 | ) 32 | 33 | cc_library( 34 | name = "channel", 35 | srcs = ["channel.c"], 36 | deps = [ 37 | ":channel_hdr", 38 | ":endpoint", 39 | ":mam_channel_t_set", 40 | "//mam/pb3", 41 | ], 42 | ) 43 | 44 | cc_library( 45 | name = "endpoint_hdr", 46 | hdrs = ["endpoint.h"], 47 | deps = [ 48 | "//mam/mss", 49 | "//mam/trits", 50 | ], 51 | ) 52 | 53 | cc_library( 54 | name = "endpoint", 55 | srcs = ["endpoint.c"], 56 | deps = [ 57 | ":endpoint_hdr", 58 | ":mam_endpoint_t_set", 59 | "//mam/pb3", 60 | ], 61 | ) 62 | 63 | typed_container_generate( 64 | additional_deps = ":endpoint_hdr", 65 | additional_include_path = "mam/mam/endpoint.h", 66 | container_type = "set", 67 | parent_directory = "mam/mam", 68 | value_type = "mam_endpoint_t", 69 | ) 70 | 71 | typed_container_generate( 72 | additional_deps = "channel_hdr", 73 | additional_include_path = "mam/mam/channel.h", 74 | container_type = "set", 75 | parent_directory = "mam/mam", 76 | value_type = "mam_channel_t", 77 | ) 78 | 79 | typed_container_generate( 80 | additional_deps = "channel_hdr", 81 | additional_include_path = "mam/mam/channel.h", 82 | container_type = "set", 83 | parent_directory = "mam/mam", 84 | value_type = "mam_pk_t", 85 | ) 86 | -------------------------------------------------------------------------------- /mam/mam/channel.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https://github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by 6 | * [ITSec Lab] 7 | * 8 | * Refer to the LICENSE file for licensing information 9 | */ 10 | 11 | /** 12 | * @ingroup mam 13 | * 14 | * @{ 15 | * 16 | * @file 17 | * @brief 18 | * 19 | */ 20 | #ifndef __MAM_MAM_CHANNEL_H__ 21 | #define __MAM_MAM_CHANNEL_H__ 22 | 23 | #include "common/trinary/add.h" 24 | #include "mam/mam/mam_endpoint_t_set.h" 25 | #include "mam/mss/mss.h" 26 | #include "mam/trits/trits.h" 27 | 28 | #define MAM_CHANNEL_ID_TRIT_SIZE MAM_MSS_MT_HASH_SIZE 29 | #define MAM_CHANNEL_ID_TRYTE_SIZE (MAM_CHANNEL_ID_TRIT_SIZE / 3) 30 | #define MAM_CHANNEL_NAME_SIZE 18 31 | #define MAM_CHANNEL_MSG_ORD_SIZE 81 32 | 33 | #ifdef __cplusplus 34 | extern "C" { 35 | #endif 36 | 37 | typedef struct mam_channel_s { 38 | trits_t name_size; 39 | trits_t name; 40 | trit_t msg_ord[MAM_CHANNEL_MSG_ORD_SIZE]; 41 | mam_mss_t mss; 42 | mam_endpoint_t_set_t endpoints; 43 | trint18_t endpoint_ord; 44 | } mam_channel_t; 45 | 46 | typedef struct mam_channel_t_set_entry_s mam_channel_t_set_entry_t; 47 | typedef mam_channel_t_set_entry_t *mam_channel_t_set_t; 48 | 49 | typedef struct mam_pk_s { 50 | trit_t key[MAM_CHANNEL_ID_TRIT_SIZE]; 51 | } mam_pk_t; 52 | 53 | /** 54 | * Gets a channel's id 55 | * 56 | * @param channel The channel 57 | * 58 | * @return the channel's id 59 | */ 60 | static inline trits_t mam_channel_id(mam_channel_t const *const channel) { 61 | return trits_from_rep(MAM_CHANNEL_ID_TRIT_SIZE, channel->mss.root); 62 | } 63 | 64 | /** 65 | * Gets a channel's name size 66 | * 67 | * @param channel The channel 68 | * 69 | * @return the channel's name size 70 | */ 71 | static inline trits_t mam_channel_name_size(mam_channel_t const *const channel) { return channel->name_size; } 72 | 73 | /** 74 | * Gets a channel's name 75 | * 76 | * @param channel The channel 77 | * 78 | * @return the channel's name 79 | */ 80 | static inline trits_t mam_channel_name(mam_channel_t const *const channel) { return channel->name; } 81 | 82 | /** 83 | * Gets a channel's msg_ord 84 | * 85 | * @param channel The channel 86 | * 87 | * @return the channel's msg_ord 88 | */ 89 | static inline trits_t mam_channel_msg_ord(mam_channel_t const *const channel) { 90 | return trits_from_rep(MAM_CHANNEL_MSG_ORD_SIZE, channel->msg_ord); 91 | } 92 | 93 | /** 94 | * Allocates memory for internal objects, and generates MSS public key 95 | * 96 | * @param allocator A MAM allocator 97 | * @param prng A shared PRNG interface used to generate WOTS private keys 98 | * @param height MSS MT height 99 | * @param channel_name The channel name 100 | * @param channel The channel 101 | * 102 | * @return a status code 103 | */ 104 | retcode_t mam_channel_create(mam_prng_t *const prng, mss_mt_height_t const height, trits_t const channel_name, 105 | mam_channel_t *const channel); 106 | 107 | /** 108 | * Returns the number of remaining secret keys (unused leaves on merkle tree) 109 | * @param channel The channel 110 | * 111 | * @return number of remaining secret keys 112 | */ 113 | static inline size_t mam_channel_remaining_sks(mam_channel_t const *const channel) { 114 | return channel ? mam_mss_remaining_sks(&channel->mss) : 0; 115 | } 116 | 117 | /** 118 | * Deallocates memory for internal objects 119 | * Before destroying channel, make sure to destroy all associated endpoints 120 | * 121 | * @param allocator A MAM allocator 122 | * @param channel The channel 123 | */ 124 | void mam_channel_destroy(mam_channel_t *const channel); 125 | 126 | retcode_t mam_channels_destroy(mam_channel_t_set_t *const channels); 127 | 128 | size_t mam_channel_serialized_size(mam_channel_t const *const channel); 129 | 130 | void mam_channel_serialize(mam_channel_t const *const channel, trits_t *const buffer); 131 | 132 | retcode_t mam_channel_deserialize(trits_t *const buffer, mam_prng_t *const prng, mam_channel_t *const channel); 133 | 134 | size_t mam_channels_serialized_size(mam_channel_t_set_t const channels); 135 | 136 | void mam_channels_serialize(mam_channel_t_set_t const channels, trits_t *const buffer); 137 | 138 | retcode_t mam_channels_deserialize(trits_t *const buffer, mam_prng_t *const prng, mam_channel_t_set_t *const channels); 139 | 140 | #ifdef __cplusplus 141 | } 142 | #endif 143 | 144 | #endif // __MAM_MAM_CHANNEL_H__ 145 | 146 | /** @} */ 147 | -------------------------------------------------------------------------------- /mam/mam/endpoint.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https://github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by 6 | * [ITSec Lab] 7 | * 8 | * Refer to the LICENSE file for licensing information 9 | */ 10 | 11 | #include "mam/mam/endpoint.h" 12 | #include "common/defs.h" 13 | #include "mam/mam/mam_endpoint_t_set.h" 14 | #include "mam/pb3/pb3.h" 15 | 16 | retcode_t mam_endpoint_create(mam_prng_t *const prng, mss_mt_height_t const height, trits_t const channel_name_size, 17 | trits_t const channel_name, trits_t const name, mam_endpoint_t *const endpoint) { 18 | MAM_ASSERT(endpoint); 19 | MAM_ASSERT(height <= MAM_MSS_MAX_D); 20 | 21 | retcode_t ret = RC_OK; 22 | size_t name_size = trits_size(name); 23 | trits_t name_size_trits = trits_null(); 24 | 25 | MAM_ASSERT(name_size % NUMBER_OF_TRITS_IN_A_TRYTE == 0); 26 | 27 | memset(endpoint, 0, sizeof(mam_endpoint_t)); 28 | 29 | if (trits_is_null(endpoint->name_size = trits_alloc(MAM_TRITS_MAX_SIZEOF_SIZE_T))) { 30 | ret = RC_OOM; 31 | goto done; 32 | } 33 | name_size_trits = mam_endpoint_name_size(endpoint); 34 | trits_set_zero(name_size_trits); 35 | trits_encode_size_t(name_size / NUMBER_OF_TRITS_IN_A_TRYTE, &name_size_trits); 36 | 37 | if (trits_is_null(endpoint->name = trits_alloc(name_size))) { 38 | ret = RC_OOM; 39 | goto done; 40 | } 41 | trits_copy(name, endpoint->name); 42 | 43 | if ((ret = mam_mss_create(&endpoint->mss, height)) != RC_OK) { 44 | goto done; 45 | } 46 | 47 | mam_mss_init(&endpoint->mss, prng, height, channel_name_size, channel_name, mam_endpoint_name_size(endpoint), 48 | mam_endpoint_name(endpoint)); 49 | 50 | mam_mss_gen(&endpoint->mss); 51 | 52 | done: 53 | 54 | if (ret != RC_OK) { 55 | trits_free(endpoint->name_size); 56 | trits_free(endpoint->name); 57 | } 58 | 59 | return ret; 60 | } 61 | 62 | void mam_endpoint_destroy(mam_endpoint_t *const endpoint) { 63 | MAM_ASSERT(endpoint); 64 | trits_free(endpoint->name_size); 65 | trits_free(endpoint->name); 66 | mam_mss_destroy(&endpoint->mss); 67 | } 68 | 69 | retcode_t mam_endpoints_destroy(mam_endpoint_t_set_t *const endpoints) { 70 | mam_endpoint_t_set_entry_t *entry = NULL; 71 | mam_endpoint_t_set_entry_t *tmp = NULL; 72 | 73 | if (endpoints == NULL || *endpoints == NULL) { 74 | return RC_OK; 75 | } 76 | 77 | SET_ITER(*endpoints, entry, tmp) { 78 | mam_endpoint_destroy(&entry->value); 79 | mam_endpoint_t_set_remove_entry(endpoints, entry); 80 | } 81 | 82 | return RC_OK; 83 | } 84 | 85 | size_t mam_endpoint_serialized_size(mam_endpoint_t const *const endpoint) { 86 | return pb3_sizeof_ntrytes(MAM_TRITS_MAX_SIZEOF_SIZE_T / NUMBER_OF_TRITS_IN_A_TRYTE) + // name size 87 | pb3_sizeof_ntrytes(trits_size(endpoint->name) / NUMBER_OF_TRITS_IN_A_TRYTE) + // name 88 | pb3_sizeof_ntrytes(mam_mss_serialized_size(&endpoint->mss) / NUMBER_OF_TRITS_IN_A_TRYTE); // mss 89 | } 90 | 91 | void mam_endpoint_serialize(mam_endpoint_t const *const endpoint, trits_t *const buffer) { 92 | pb3_encode_ntrytes(mam_endpoint_name_size(endpoint), buffer); // name size 93 | pb3_encode_ntrytes(mam_endpoint_name(endpoint), buffer); // name 94 | mam_mss_serialize(&endpoint->mss, buffer); // mss 95 | } 96 | 97 | retcode_t mam_endpoint_deserialize(trits_t *const buffer, trits_t const channel_name_size, trits_t const channel_name, 98 | mam_prng_t *const prng, mam_endpoint_t *const endpoint) { 99 | MAM_ASSERT(!trits_is_null(channel_name)); 100 | 101 | retcode_t ret = RC_OK; 102 | size_t size = 0; 103 | mss_mt_height_t height = 0; 104 | trits_t name_size_trits = trits_null(); 105 | 106 | if (trits_is_null(endpoint->name_size = trits_alloc(MAM_TRITS_MAX_SIZEOF_SIZE_T))) { 107 | ret = RC_OOM; 108 | goto done; 109 | } 110 | name_size_trits = mam_endpoint_name_size(endpoint); 111 | 112 | if ((ret = pb3_decode_ntrytes(mam_endpoint_name_size(endpoint), buffer)) != RC_OK) { // name size 113 | goto done; 114 | } 115 | 116 | if ((ret = pb3_decode_size_t(&size, &name_size_trits)) != RC_OK) { 117 | goto done; 118 | } 119 | 120 | if (trits_is_null(endpoint->name = trits_alloc(size * NUMBER_OF_TRITS_IN_A_TRYTE))) { 121 | ret = RC_OOM; 122 | goto done; 123 | } 124 | if ((ret = pb3_decode_ntrytes(mam_endpoint_name(endpoint), buffer)) != RC_OK) { // name 125 | goto done; 126 | } 127 | 128 | MAM_TRITS_DEF(ts, MAM_MSS_SKN_SIZE); 129 | ts = MAM_TRITS_INIT(ts, MAM_MSS_SKN_SIZE); 130 | trits_set_zero(ts); 131 | 132 | trits_copy(trits_take(*buffer, 4), trits_take(ts, 4)); 133 | height = trits_get6(ts); 134 | 135 | if ((ret = mam_mss_create(&endpoint->mss, height)) != RC_OK) { 136 | goto done; 137 | } 138 | 139 | mam_mss_init(&endpoint->mss, prng, height, channel_name_size, channel_name, mam_endpoint_name_size(endpoint), 140 | mam_endpoint_name(endpoint)); 141 | 142 | if ((ret = mam_mss_deserialize(buffer, &endpoint->mss)) != RC_OK) { 143 | mam_mss_destroy(&endpoint->mss); 144 | goto done; 145 | } 146 | 147 | done: 148 | 149 | if (ret != RC_OK) { 150 | trits_free(endpoint->name_size); 151 | trits_free(endpoint->name); 152 | } 153 | 154 | return ret; 155 | } 156 | 157 | size_t mam_endpoints_serialized_size(mam_endpoint_t_set_t const endpoints) { 158 | mam_endpoint_t_set_entry_t *entry = NULL; 159 | mam_endpoint_t_set_entry_t *tmp = NULL; 160 | size_t size = pb3_sizeof_size_t(mam_endpoint_t_set_size(endpoints)); // endpoints number 161 | 162 | SET_ITER(endpoints, entry, tmp) { // endpoint 163 | size += mam_endpoint_serialized_size(&entry->value); 164 | } 165 | 166 | return size; 167 | } 168 | 169 | void mam_endpoints_serialize(mam_endpoint_t_set_t const endpoints, trits_t *const buffer) { 170 | mam_endpoint_t_set_entry_t *entry = NULL; 171 | mam_endpoint_t_set_entry_t *tmp = NULL; 172 | 173 | pb3_encode_size_t(mam_endpoint_t_set_size(endpoints), 174 | buffer); // endpoints number 175 | 176 | SET_ITER(endpoints, entry, tmp) { mam_endpoint_serialize(&entry->value, buffer); } 177 | } 178 | 179 | retcode_t mam_endpoints_deserialize(trits_t *const buffer, trits_t const channel_name_size, trits_t const channel_name, 180 | mam_prng_t *const prng, mam_endpoint_t_set_t *const endpoints) { 181 | retcode_t ret = RC_OK; 182 | mam_endpoint_t endpoint; 183 | size_t size = 0; 184 | 185 | if ((ret = pb3_decode_size_t(&size, buffer)) != RC_OK) { // endpoints number 186 | return ret; 187 | } 188 | 189 | while (size--) { 190 | if ((ret = mam_endpoint_deserialize(buffer, channel_name_size, channel_name, prng, 191 | &endpoint)) != RC_OK) { // endpoint 192 | return ret; 193 | } 194 | if ((ret = mam_endpoint_t_set_add(endpoints, &endpoint)) != RC_OK) { 195 | return ret; 196 | } 197 | } 198 | 199 | return ret; 200 | } 201 | -------------------------------------------------------------------------------- /mam/mam/endpoint.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https://github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by 6 | * [ITSec Lab] 7 | * 8 | * Refer to the LICENSE file for licensing information 9 | */ 10 | 11 | /** 12 | * @ingroup mam 13 | * 14 | * @{ 15 | * 16 | * @file 17 | * @brief 18 | * 19 | */ 20 | #ifndef __MAM_MAM_ENDPOINT_H__ 21 | #define __MAM_MAM_ENDPOINT_H__ 22 | 23 | #include "mam/mss/mss.h" 24 | #include "mam/trits/trits.h" 25 | 26 | #define MAM_ENDPOINT_ID_TRIT_SIZE MAM_MSS_MT_HASH_SIZE 27 | #define MAM_ENDPOINT_ID_TRYTE_SIZE (MAM_ENDPOINT_ID_TRIT_SIZE / 3) 28 | #define MAM_ENDPOINT_NAME_SIZE 18 29 | 30 | #ifdef __cplusplus 31 | extern "C" { 32 | #endif 33 | 34 | typedef struct mam_endpoint_s { 35 | trits_t name_size; 36 | trits_t name; 37 | mam_mss_t mss; 38 | } mam_endpoint_t; 39 | 40 | typedef struct mam_endpoint_t_set_entry_s mam_endpoint_t_set_entry_t; 41 | typedef mam_endpoint_t_set_entry_t *mam_endpoint_t_set_t; 42 | 43 | /** 44 | * Gets an endpoint's id 45 | * 46 | * @param endpoint The endpoint 47 | * 48 | * @return the endpoint's id 49 | */ 50 | static inline trits_t mam_endpoint_id(mam_endpoint_t const *const endpoint) { 51 | return trits_from_rep(MAM_ENDPOINT_ID_TRIT_SIZE, endpoint->mss.root); 52 | } 53 | 54 | /** 55 | * Gets an endpoint's name size 56 | * 57 | * @param endpoint The endpoint 58 | * 59 | * @return the endpoint's name size 60 | */ 61 | static inline trits_t mam_endpoint_name_size(mam_endpoint_t const *const endpoint) { return endpoint->name_size; } 62 | 63 | /** 64 | * Gets an endpoint's name 65 | * 66 | * @param endpoint The endpoint 67 | * 68 | * @return the endpoint's name 69 | */ 70 | static inline trits_t mam_endpoint_name(mam_endpoint_t const *const endpoint) { return endpoint->name; } 71 | 72 | /** 73 | * Allocates memory for internal objects and generates MSS public key 74 | * 75 | * @param allocator A MAM allocator 76 | * @param prng A shared PRNG interface used to generate WOTS private keys 77 | * @param height MSS MT height 78 | * @param channel_name_size The channel name size 79 | * @param channel_name The channel name 80 | * @param endpoint_name The endpoint name 81 | * @param endpoint The endpoint 82 | * 83 | * @return a status code 84 | */ 85 | retcode_t mam_endpoint_create(mam_prng_t *const prng, mss_mt_height_t const height, trits_t const channel_name_size, 86 | trits_t const channel_name, trits_t const endpoint_name, mam_endpoint_t *const endpoint); 87 | 88 | /** 89 | * Returns the number of remaining secret keys (unused leaves on merkle tree) 90 | * @param endpoint The endpoint 91 | * 92 | * @return number of remaining secret keys 93 | */ 94 | static inline size_t mam_endpoint_remaining_sks(mam_endpoint_t const *const endpoint) { 95 | return endpoint ? mam_mss_remaining_sks(&endpoint->mss) : 0; 96 | } 97 | 98 | /** 99 | * Deallocates memory for internal objects 100 | * 101 | * @param allocator A MAM allocator 102 | * @param endpoint The endpoint 103 | */ 104 | void mam_endpoint_destroy(mam_endpoint_t *const endpoint); 105 | 106 | retcode_t mam_endpoints_destroy(mam_endpoint_t_set_t *const endpoints); 107 | 108 | size_t mam_endpoint_serialized_size(mam_endpoint_t const *const endpoint); 109 | 110 | void mam_endpoint_serialize(mam_endpoint_t const *const endpoint, trits_t *const buffer); 111 | 112 | retcode_t mam_endpoint_deserialize(trits_t *const buffer, trits_t const channel_name_size, trits_t const channel_name, 113 | mam_prng_t *const prng, mam_endpoint_t *const endpoint); 114 | 115 | size_t mam_endpoints_serialized_size(mam_endpoint_t_set_t const endpoints); 116 | 117 | void mam_endpoints_serialize(mam_endpoint_t_set_t const endpoints, trits_t *const buffer); 118 | 119 | retcode_t mam_endpoints_deserialize(trits_t *const buffer, trits_t const channel_name_size, trits_t const channel_name, 120 | mam_prng_t *const prng, mam_endpoint_t_set_t *const endpoints); 121 | 122 | #ifdef __cplusplus 123 | } 124 | #endif 125 | 126 | #endif // __MAM_MAM_ENDPOINT_H__ 127 | 128 | /** @} */ 129 | -------------------------------------------------------------------------------- /mam/mam/tests/BUILD: -------------------------------------------------------------------------------- 1 | cc_library( 2 | name = "test_channel_utils", 3 | srcs = ["test_channel_utils.c"], 4 | hdrs = ["test_channel_utils.h"], 5 | visibility = ["//visibility:public"], 6 | deps = [ 7 | "//mam/mam:channel", 8 | "//mam/mam:mam_channel_t_set", 9 | ], 10 | ) 11 | 12 | cc_test( 13 | name = "test_message", 14 | timeout = "eternal", 15 | srcs = ["test_message.c"], 16 | deps = [ 17 | "//mam/mam:message", 18 | "@unity", 19 | ], 20 | ) 21 | 22 | cc_test( 23 | name = "test_endpoint", 24 | timeout = "long", 25 | srcs = ["test_endpoint.c"], 26 | deps = [ 27 | "//mam/mam:endpoint", 28 | "//mam/mam:mam_endpoint_t_set", 29 | "//mam/mam:message", 30 | "@unity", 31 | ], 32 | ) 33 | 34 | cc_test( 35 | name = "test_channel", 36 | timeout = "long", 37 | srcs = ["test_channel.c"], 38 | deps = [ 39 | ":test_channel_utils", 40 | "//mam/mam:message", 41 | "@unity", 42 | ], 43 | ) 44 | -------------------------------------------------------------------------------- /mam/mam/tests/test_channel.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https:github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by 6 | * [ITSec Lab] 7 | * 8 | * Refer to the LICENSE file for licensing information 9 | */ 10 | 11 | #include 12 | 13 | #include 14 | 15 | #include "common/trinary/trit_tryte.h" 16 | #include "mam/mam/channel.h" 17 | #include "mam/mam/mam_channel_t_set.h" 18 | #include "mam/mam/message.h" 19 | #include "mam/mam/tests/test_channel_utils.h" 20 | 21 | void test_channel(void) { 22 | mam_channel_t channel; 23 | mam_channel_t_set_t channels_1 = NULL; 24 | mam_channel_t_set_t channels_2 = NULL; 25 | 26 | mam_prng_t prng; 27 | tryte_t channel_name[27]; 28 | trits_t channel_name_trits = trits_alloc(81); 29 | 30 | MAM_TRITS_DEF(prng_key, MAM_PRNG_SECRET_KEY_SIZE); 31 | prng_key = MAM_TRITS_INIT(prng_key, MAM_PRNG_SECRET_KEY_SIZE); 32 | trits_from_str(prng_key, 33 | "NOPQRSTUVWXYZ9ABCDEFGHIJKLM" 34 | "NOPQRSTUVWXYZ9ABCDEFGHIJKLM" 35 | "NOPQRSTUVWXYZ9ABCDEFGHIJKLM"); 36 | 37 | mam_prng_init(&prng, prng_key); 38 | 39 | for (size_t i = 1; i < 5; i++) { 40 | memset(channel_name, 'A' + 2 * i, 27); 41 | trytes_to_trits(channel_name, channel_name_trits.p, 27); 42 | TEST_ASSERT(mam_channel_create(&prng, i, channel_name_trits, &channel) == RC_OK); 43 | add_assign(channel.msg_ord, MAM_CHANNEL_MSG_ORD_SIZE, i); 44 | channel.endpoint_ord = i; 45 | TEST_ASSERT(mam_channel_t_set_add(&channels_1, &channel) == RC_OK); 46 | } 47 | 48 | size_t size = mam_channels_serialized_size(channels_1); 49 | 50 | trits_t trits = trits_alloc(size); 51 | trits_t cpy = trits; 52 | 53 | mam_channels_serialize(channels_1, &trits); 54 | 55 | TEST_ASSERT(mam_channels_deserialize(&cpy, &prng, &channels_2) == RC_OK); 56 | 57 | TEST_ASSERT_TRUE(mam_channel_t_set_cmp_test(channels_1, channels_2)); 58 | 59 | mam_channels_destroy(&channels_1); 60 | mam_channels_destroy(&channels_2); 61 | trits_free(trits); 62 | trits_free(channel_name_trits); 63 | } 64 | 65 | int main(void) { 66 | UNITY_BEGIN(); 67 | 68 | RUN_TEST(test_channel); 69 | 70 | return UNITY_END(); 71 | } 72 | -------------------------------------------------------------------------------- /mam/mam/tests/test_channel_utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https:github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by 6 | * [ITSec Lab] 7 | * 8 | * Refer to the LICENSE file for licensing information 9 | */ 10 | 11 | #include "mam/mam/channel.h" 12 | #include "mam/mam/mam_channel_t_set.h" 13 | 14 | bool mam_channel_t_set_cmp_test(mam_channel_t_set_t const channels_1, mam_channel_t_set_t const channels_2) { 15 | mam_channel_t_set_entry_t *entry_1 = NULL; 16 | mam_channel_t_set_entry_t *tmp_1 = NULL; 17 | mam_channel_t_set_entry_t *entry_2 = NULL; 18 | mam_channel_t_set_entry_t *tmp_2 = NULL; 19 | size_t match = 0; 20 | MAM_TRITS_DEF(hash, MAM_MSS_HASH_SIZE); 21 | hash = MAM_TRITS_INIT(hash, MAM_MSS_HASH_SIZE); 22 | trits_from_str(hash, 23 | "ABCNKOZWYSDF9OABCNKOZWYSDF9" 24 | "ABCNKOZWYSDF9QABCNKOZWYSDF9" 25 | "ABCNKOZWYSDF9CABCNKOZWYSDF9"); 26 | 27 | if (mam_channel_t_set_size(channels_1) != mam_channel_t_set_size(channels_2)) { 28 | return false; 29 | } 30 | 31 | HASH_ITER(hh, channels_1, entry_1, tmp_1) { 32 | HASH_ITER(hh, channels_2, entry_2, tmp_2) { 33 | if (memcmp(entry_1->value.mss.root, entry_2->value.mss.root, MAM_ENDPOINT_ID_TRIT_SIZE) == 0) { 34 | if (!trits_cmp_eq(entry_1->value.name_size, entry_2->value.name_size)) { 35 | continue; 36 | } 37 | if (!trits_cmp_eq(entry_1->value.name, entry_2->value.name)) { 38 | continue; 39 | } 40 | if (memcmp(entry_1->value.msg_ord, entry_2->value.msg_ord, MAM_CHANNEL_MSG_ORD_SIZE) != 0) { 41 | continue; 42 | } 43 | if (entry_1->value.endpoint_ord != entry_2->value.endpoint_ord) { 44 | continue; 45 | } 46 | MAM_TRITS_DEF(sig1, MAM_MSS_SIG_SIZE(entry_1->value.mss.height)); 47 | MAM_TRITS_DEF(sig2, MAM_MSS_SIG_SIZE(entry_2->value.mss.height)); 48 | sig1 = MAM_TRITS_INIT(sig1, MAM_MSS_SIG_SIZE(entry_1->value.mss.height)); 49 | sig2 = MAM_TRITS_INIT(sig2, MAM_MSS_SIG_SIZE(entry_2->value.mss.height)); 50 | if (mam_mss_sign(&entry_1->value.mss, hash, sig1) != RC_OK) { 51 | continue; 52 | } 53 | if (mam_mss_sign(&entry_2->value.mss, hash, sig2) != RC_OK) { 54 | continue; 55 | } 56 | if (trits_cmp_eq(sig1, sig2)) { 57 | match++; 58 | break; 59 | } 60 | // TODO check endpoints 61 | } 62 | } 63 | } 64 | 65 | return match == mam_channel_t_set_size(channels_1); 66 | } 67 | -------------------------------------------------------------------------------- /mam/mam/tests/test_channel_utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https://github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by 6 | * [ITSec Lab] 7 | * 8 | * Refer to the LICENSE file for licensing information 9 | */ 10 | 11 | #ifndef __MAM_MAM_TESTS_TEST_CHANNEL_UTILS_H__ 12 | #define __MAM_MAM_TESTS_TEST_CHANNEL_UTILS_H__ 13 | 14 | #ifdef __cplusplus 15 | extern "C" { 16 | #endif 17 | 18 | bool mam_channel_t_set_cmp_test(mam_channel_t_set_t const channels_1, mam_channel_t_set_t const channels_2); 19 | 20 | #ifdef __cplusplus 21 | } 22 | #endif 23 | 24 | #endif // __MAM_MAM_TESTS_TEST_CHANNEL_UTILS_H__ 25 | -------------------------------------------------------------------------------- /mam/mam/tests/test_endpoint.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https:github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by 6 | * [ITSec Lab] 7 | * 8 | * Refer to the LICENSE file for licensing information 9 | */ 10 | 11 | #include 12 | 13 | #include 14 | 15 | #include "common/trinary/trit_tryte.h" 16 | #include "mam/mam/endpoint.h" 17 | #include "mam/mam/mam_endpoint_t_set.h" 18 | 19 | #define CHANNEL_NAME_SIZE 27 20 | #define ENDPOINT_NAME_SIZE 27 21 | 22 | static bool mam_endpoint_t_set_cmp_test_endpoints(mam_endpoint_t_set_t const endpoints_1, 23 | mam_endpoint_t_set_t const endpoints_2) { 24 | mam_endpoint_t_set_entry_t *entry_1 = NULL; 25 | mam_endpoint_t_set_entry_t *tmp_1 = NULL; 26 | mam_endpoint_t_set_entry_t *entry_2 = NULL; 27 | mam_endpoint_t_set_entry_t *tmp_2 = NULL; 28 | size_t match = 0; 29 | MAM_TRITS_DEF(hash, MAM_MSS_HASH_SIZE); 30 | hash = MAM_TRITS_INIT(hash, MAM_MSS_HASH_SIZE); 31 | trits_from_str(hash, 32 | "ABCNKOZWYSDF9OABCNKOZWYSDF9" 33 | "ABCNKOZWYSDF9QABCNKOZWYSDF9" 34 | "ABCNKOZWYSDF9CABCNKOZWYSDF9"); 35 | 36 | if (mam_endpoint_t_set_size(endpoints_1) != mam_endpoint_t_set_size(endpoints_2)) { 37 | return false; 38 | } 39 | 40 | HASH_ITER(hh, endpoints_1, entry_1, tmp_1) { 41 | HASH_ITER(hh, endpoints_2, entry_2, tmp_2) { 42 | if (memcmp(entry_1->value.mss.root, entry_2->value.mss.root, MAM_ENDPOINT_ID_TRIT_SIZE) == 0) { 43 | if (!trits_cmp_eq(entry_1->value.name_size, entry_2->value.name_size)) { 44 | continue; 45 | } 46 | if (!trits_cmp_eq(entry_1->value.name, entry_2->value.name)) { 47 | continue; 48 | } 49 | MAM_TRITS_DEF(sig1, MAM_MSS_SIG_SIZE(entry_1->value.mss.height)); 50 | MAM_TRITS_DEF(sig2, MAM_MSS_SIG_SIZE(entry_2->value.mss.height)); 51 | sig1 = MAM_TRITS_INIT(sig1, MAM_MSS_SIG_SIZE(entry_1->value.mss.height)); 52 | sig2 = MAM_TRITS_INIT(sig2, MAM_MSS_SIG_SIZE(entry_2->value.mss.height)); 53 | TEST_ASSERT(mam_mss_sign(&entry_1->value.mss, hash, sig1) == RC_OK); 54 | TEST_ASSERT(mam_mss_sign(&entry_2->value.mss, hash, sig2) == RC_OK); 55 | if (trits_cmp_eq(sig1, sig2)) { 56 | match++; 57 | break; 58 | } 59 | } 60 | } 61 | } 62 | 63 | return match == mam_endpoint_t_set_size(endpoints_1); 64 | } 65 | 66 | void test_endpoint(void) { 67 | mam_endpoint_t endpoint; 68 | mam_endpoint_t_set_t endpoints_1 = NULL; 69 | mam_endpoint_t_set_t endpoints_2 = NULL; 70 | 71 | mam_sponge_t sponge; 72 | mam_prng_t prng; 73 | tryte_t channel_name[CHANNEL_NAME_SIZE]; 74 | trits_t channel_name_trits = trits_alloc(CHANNEL_NAME_SIZE * 3); 75 | trits_t channel_name_size_trits = trits_alloc(MAM_TRITS_MAX_SIZEOF_SIZE_T); 76 | tryte_t endpoint_name[ENDPOINT_NAME_SIZE]; 77 | trits_t endpoint_name_trits = trits_alloc(ENDPOINT_NAME_SIZE * 3); 78 | 79 | MAM_TRITS_DEF(prng_key, MAM_PRNG_SECRET_KEY_SIZE); 80 | prng_key = MAM_TRITS_INIT(prng_key, MAM_PRNG_SECRET_KEY_SIZE); 81 | trits_from_str(prng_key, 82 | "NOPQRSTUVWXYZ9ABCDEFGHIJKLM" 83 | "NOPQRSTUVWXYZ9ABCDEFGHIJKLM" 84 | "NOPQRSTUVWXYZ9ABCDEFGHIJKLM"); 85 | 86 | mam_sponge_init(&sponge); 87 | mam_prng_init(&prng, prng_key); 88 | 89 | memset(channel_name, 'I', CHANNEL_NAME_SIZE); 90 | trytes_to_trits(channel_name, trits_begin(channel_name_trits), CHANNEL_NAME_SIZE); 91 | trits_encode_size_t(trits_size(channel_name_trits) / NUMBER_OF_TRITS_IN_A_TRYTE, &channel_name_size_trits); 92 | 93 | for (size_t i = 1; i < 5; i++) { 94 | memset(endpoint_name, 'A' + 2 * i + 1, ENDPOINT_NAME_SIZE); 95 | trytes_to_trits(endpoint_name, trits_begin(endpoint_name_trits), ENDPOINT_NAME_SIZE); 96 | TEST_ASSERT(mam_endpoint_create(&prng, i, channel_name_size_trits, channel_name_trits, endpoint_name_trits, 97 | &endpoint) == RC_OK); 98 | TEST_ASSERT(mam_endpoint_t_set_add(&endpoints_1, &endpoint) == RC_OK); 99 | } 100 | 101 | size_t size = mam_endpoints_serialized_size(endpoints_1); 102 | trits_t trits = trits_alloc(size); 103 | trits_t cpy = trits; 104 | 105 | mam_endpoints_serialize(endpoints_1, &trits); 106 | 107 | TEST_ASSERT(mam_endpoints_deserialize(&cpy, channel_name_size_trits, channel_name_trits, &prng, &endpoints_2) == 108 | RC_OK); 109 | 110 | TEST_ASSERT_TRUE(mam_endpoint_t_set_cmp_test_endpoints(endpoints_1, endpoints_2)); 111 | 112 | mam_endpoints_destroy(&endpoints_1); 113 | mam_endpoints_destroy(&endpoints_2); 114 | trits_free(trits); 115 | trits_free(channel_name_trits); 116 | trits_free(channel_name_size_trits); 117 | trits_free(endpoint_name_trits); 118 | } 119 | 120 | int main(void) { 121 | UNITY_BEGIN(); 122 | 123 | RUN_TEST(test_endpoint); 124 | 125 | return UNITY_END(); 126 | } 127 | -------------------------------------------------------------------------------- /mam/mss/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//visibility:public"]) 2 | 3 | config_setting( 4 | name = "merkle_traversal", 5 | values = {"define": "merkle_mode=traversal"}, 6 | ) 7 | 8 | config_setting( 9 | name = "merkle_classic", 10 | values = {"define": "merkle_mode=classic"}, 11 | ) 12 | 13 | cc_library( 14 | name = "mss", 15 | deps = 16 | select({ 17 | ":merkle_traversal": [":mss_traversal"], 18 | ":merkle_classic": [":mss_classic"], 19 | "//conditions:default": [":mss_traversal"], 20 | }), 21 | ) 22 | 23 | cc_library( 24 | name = "mss_traversal", 25 | srcs = [ 26 | "mss_common.c", 27 | "mss_traversal.c", 28 | ], 29 | hdrs = [ 30 | "mss.h", 31 | "mss_common.h", 32 | "mss_traversal.h", 33 | ], 34 | defines = ["MAM_MSS_TRAVERSAL"], 35 | deps = [ 36 | "//mam/wots", 37 | "@org_iota_common//common:errors", 38 | ], 39 | ) 40 | 41 | cc_library( 42 | name = "mss_classic", 43 | srcs = [ 44 | "mss_classic.c", 45 | "mss_common.c", 46 | ], 47 | hdrs = [ 48 | "mss.h", 49 | "mss_classic.h", 50 | "mss_common.h", 51 | ], 52 | deps = [ 53 | "//mam/wots", 54 | "@org_iota_common//common:errors", 55 | ], 56 | ) 57 | -------------------------------------------------------------------------------- /mam/mss/mss.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 IOTA Stiftung 3 | * https://github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by [ITSec Lab] 6 | * 7 | * Refer to the LICENSE file for licensing information 8 | */ 9 | 10 | /** 11 | * @ingroup mam 12 | * 13 | * @{ 14 | * 15 | * @file 16 | * @brief 17 | * 18 | */ 19 | #ifndef __MAM_MSS_MSS_H__ 20 | #define __MAM_MSS_MSS_H__ 21 | 22 | #include "mam/mss/mss_common.h" 23 | 24 | #if defined(MAM_MSS_TRAVERSAL) 25 | #include "mam/mss/mss_traversal.h" 26 | #else 27 | #include "mam/mss/mss_classic.h" 28 | #endif 29 | 30 | #endif // __MAM_MSS_MSS_H__ 31 | 32 | /** @} */ 33 | -------------------------------------------------------------------------------- /mam/mss/mss_classic.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 IOTA Stiftung 3 | * https://github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by [ITSec Lab] 6 | * 7 | * Refer to the LICENSE file for licensing information 8 | */ 9 | 10 | #include 11 | 12 | #include "mam/mss/mss.h" 13 | #include "mam/pb3/pb3.h" 14 | 15 | static trits_t mss_mt_node_t_trits(mam_mss_t const *const mss, mss_mt_height_t height, mss_mt_idx_t i) { 16 | MAM_ASSERT(height <= mss->height); 17 | MAM_ASSERT(i < ((mss_mt_idx_t)1 << height)); 18 | 19 | size_t idx = ((size_t)1 << height) + i - 1; 20 | trit_t *t = mss->mt + MAM_MSS_MT_HASH_SIZE * idx; 21 | return trits_from_rep(MAM_MSS_MT_HASH_SIZE, t); 22 | } 23 | 24 | void mam_mss_init(mam_mss_t *mss, mam_prng_t *const prng, mss_mt_height_t height, trits_t nonce1, trits_t nonce2, 25 | trits_t nonce3, trits_t nonce4) { 26 | MAM_ASSERT(mss); 27 | MAM_ASSERT(prng); 28 | MAM_ASSERT(0 <= height && height <= MAM_MSS_MAX_D); 29 | 30 | mss->height = height; 31 | mss->skn = 0; 32 | mss->prng = prng; 33 | mss->nonce1 = nonce1; 34 | mss->nonce2 = nonce2; 35 | mss->nonce3 = nonce3; 36 | mss->nonce4 = nonce4; 37 | } 38 | 39 | void mam_mss_gen(mam_mss_t *mss) { 40 | trits_t root_trits = trits_from_rep(MAM_MSS_PK_SIZE, mss->root); 41 | mss_mt_height_t height; 42 | mss_mt_idx_t i, n; 43 | mam_spongos_t spongos; 44 | 45 | for (i = 0, n = (mss_mt_idx_t)1 << mss->height; i < n; ++i) { 46 | trits_t wpk = mss_mt_node_t_trits(mss, mss->height, i); 47 | mss_mt_gen_leaf(mss, i, wpk); 48 | } 49 | 50 | for (height = mss->height; height--;) { 51 | for (i = 0, n = (mss_mt_idx_t)1 << height; i < n; ++i) { 52 | trits_t h[2], h01; 53 | h[0] = mss_mt_node_t_trits(mss, height + 1, 2 * i + 0); 54 | h[1] = mss_mt_node_t_trits(mss, height + 1, 2 * i + 1); 55 | h01 = mss_mt_node_t_trits(mss, height, i); 56 | 57 | mss_hash2(&spongos, h, h01); 58 | } 59 | } 60 | 61 | trits_copy(mss_mt_node_t_trits(mss, 0, 0), root_trits); 62 | } 63 | 64 | void mam_mss_auth_path(mam_mss_t *mss, mss_mt_idx_t skn, trits_t path) { 65 | mss_mt_height_t height; 66 | trits_t path_part_out; 67 | 68 | MAM_ASSERT(trits_size(path) == MAM_MSS_APATH_SIZE(mss->height)); 69 | 70 | /* note, level height is reversed (compared to traversal): */ 71 | /* `0` is root level, `hieght` is leaf level */ 72 | for (height = mss->height; height; --height, skn = skn / 2) { 73 | path_part_out = trits_take(path, MAM_MSS_MT_HASH_SIZE); 74 | trits_t curr_auth_path_part = mss_mt_node_t_trits(mss, height, (0 == skn % 2) ? skn + 1 : skn - 1); 75 | trits_copy(curr_auth_path_part, path_part_out); 76 | path = trits_drop(path, MAM_MSS_MT_HASH_SIZE); 77 | } 78 | } 79 | 80 | bool mam_mss_next(mam_mss_t *mss) { 81 | if (mam_mss_remaining_sks(mss) == 0) { 82 | return false; 83 | } 84 | 85 | mss->skn++; 86 | 87 | return true; 88 | } 89 | 90 | retcode_t mam_mss_create(mam_mss_t *mss, mss_mt_height_t height) { 91 | MAM_ASSERT(mss); 92 | 93 | memset(mss, 0, sizeof(mam_mss_t)); 94 | ERR_GUARD_RETURN(0 <= height && height <= MAM_MSS_MAX_D, RC_MAM_INVALID_ARGUMENT); 95 | 96 | mss->mt = malloc(sizeof(trit_t) * MAM_MSS_MT_WORDS(height)); 97 | ERR_GUARD_RETURN(mss->mt, RC_OOM); 98 | 99 | /* do not free here in case of error */ 100 | return RC_OK; 101 | } 102 | 103 | void mam_mss_destroy(mam_mss_t *mss) { 104 | MAM_ASSERT(mss); 105 | 106 | if (mss->mt) { 107 | free(mss->mt); 108 | mss->mt = NULL; 109 | } 110 | } 111 | 112 | size_t mss_mt_serialized_size(mam_mss_t const *const mss) { 113 | return (((size_t)1 << (mss->height + 1)) - 1) * MAM_MSS_MT_HASH_SIZE; 114 | } 115 | 116 | void mss_mt_serialize(mam_mss_t const *const mss, trits_t *buffer) { 117 | mss_mt_height_t height; 118 | mss_mt_idx_t i; 119 | 120 | MAM_ASSERT(trits_size(*buffer) >= mss_mt_serialized_size(mss)); 121 | 122 | height = mss->height; 123 | do { 124 | for (i = 0; i != (mss_mt_idx_t)1 << height; ++i) { 125 | trits_copy(mss_mt_node_t_trits(mss, height, i), trits_take(*buffer, MAM_MSS_MT_HASH_SIZE)); 126 | *buffer = trits_drop(*buffer, MAM_MSS_MT_HASH_SIZE); 127 | } 128 | } while (height-- > 0); 129 | } 130 | 131 | static void mss_mt_deserialize(trits_t buffer, mam_mss_t *mss) { 132 | mss_mt_height_t height; 133 | mss_mt_idx_t i; 134 | 135 | MAM_ASSERT(trits_size(buffer) == mss_mt_serialized_size(mss)); 136 | 137 | /* */ 138 | height = mss->height; 139 | do { 140 | for (i = 0; i != (mss_mt_idx_t)1 << height; ++i) { 141 | trits_copy(trits_take(buffer, MAM_MSS_MT_HASH_SIZE), mss_mt_node_t_trits(mss, height, i)); 142 | buffer = trits_drop(buffer, MAM_MSS_MT_HASH_SIZE); 143 | } 144 | } while (height-- > 0); 145 | } 146 | 147 | retcode_t mam_mss_deserialize(trits_t *const buffer, mam_mss_t *const mss) { 148 | retcode_t ret = RC_OK; 149 | mss_mt_height_t height; 150 | mss_mt_idx_t skn; 151 | 152 | ERR_GUARD_RETURN(MAM_MSS_SKN_TREE_DEPTH_SIZE + MAM_MSS_SKN_KEY_NUMBER_SIZE <= trits_size(*buffer), 153 | RC_MAM_BUFFER_TOO_SMALL); 154 | ERR_GUARD_RETURN( 155 | mss_parse_skn(&height, &skn, trits_advance(buffer, MAM_MSS_SKN_TREE_DEPTH_SIZE + MAM_MSS_SKN_KEY_NUMBER_SIZE)), 156 | RC_MAM_INVALID_VALUE); 157 | ERR_GUARD_RETURN(height == mss->height, RC_MAM_INVALID_VALUE); 158 | 159 | mss->skn = skn; 160 | ERR_GUARD_RETURN(mss_mt_serialized_size(mss) <= trits_size(*buffer), RC_MAM_BUFFER_TOO_SMALL); 161 | mss_mt_deserialize(trits_advance(buffer, mss_mt_serialized_size(mss)), mss); 162 | 163 | if ((ret = pb3_decode_ntrytes(trits_from_rep(MAM_MSS_PK_SIZE, mss->root), buffer)) != RC_OK) { 164 | return ret; 165 | } 166 | 167 | return ret; 168 | } 169 | -------------------------------------------------------------------------------- /mam/mss/mss_classic.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 IOTA Stiftung 3 | * https://github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by [ITSec Lab] 6 | * 7 | * Refer to the LICENSE file for licensing information 8 | */ 9 | 10 | /** 11 | * @ingroup mam 12 | * 13 | * @{ 14 | * 15 | * @file 16 | * @brief 17 | * 18 | */ 19 | #ifndef __MAM_MSS_MSS_CLASSIC_H__ 20 | #define __MAM_MSS_MSS_CLASSIC_H__ 21 | 22 | #include "common/errors.h" 23 | #include "mam/defs.h" 24 | #include "mam/prng/prng.h" 25 | #include "mam/sponge/spongos.h" 26 | #include "mam/trits/trits.h" 27 | #include "mam/wots/wots.h" 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | /*! \brief MSS Merkle-tree implementation storage words. */ 34 | #define MAM_MSS_MT_WORDS(height) (MAM_WOTS_PUBLIC_KEY_SIZE * (2 * (1 << (height)) - 1)) 35 | #define MAM_MSS_MT_MAX_STORED_SIZE(height) (((1 << ((height) + 1)) - 1) * MAM_MSS_MT_HASH_SIZE) 36 | 37 | /*! \brief MSS interface used to generate public key and sign. */ 38 | typedef struct mam_mss_s { 39 | mss_mt_height_t height; /*!< Merkle tree height. */ 40 | mss_mt_idx_t skn; /*!< Current WOTS private key number. */ 41 | mam_prng_t *prng; /*!< PRNG interface used to generate WOTS private keys. */ 42 | trit_t *mt; /*!< Buffer storing complete Merkle-tree. */ 43 | trits_t nonce1, nonce2, nonce3, nonce4; /*!< Nonce = `N1`||`N2`||`N3`||`N4`, stored pointers only, NOT copies. */ 44 | trit_t root[MAM_MSS_PK_SIZE]; 45 | } mam_mss_t; 46 | 47 | #ifdef __cplusplus 48 | } 49 | #endif 50 | 51 | #endif // __MAM_MSS_MSS_CLASSIC_H__ 52 | 53 | /** @} */ 54 | -------------------------------------------------------------------------------- /mam/mss/mss_common.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 IOTA Stiftung 3 | * https://github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by [ITSec Lab] 6 | * 7 | * Refer to the LICENSE file for licensing information 8 | */ 9 | 10 | #include 11 | 12 | #include "mam/mss/mss.h" 13 | #include "mam/pb3/pb3.h" 14 | 15 | /*!< [in] hash values of left and right child nodes */ 16 | /*!< [out] hash value of their parent */ 17 | void mss_hash2(mam_spongos_t *s, trits_t children_hashes[2], trits_t parent_hash) { 18 | mam_spongos_hashn(s, 2, children_hashes, parent_hash); 19 | } 20 | 21 | /*!< [in] leaf index: `0 <= i < 2^D` */ 22 | /*!< [out] WOTS pk / leaf hash */ 23 | void mss_mt_gen_leaf(mam_mss_t *mss, mss_mt_idx_t i, trits_t pk) { 24 | mam_wots_t wots; 25 | mam_sponge_t sponge; 26 | 27 | MAM_TRITS_DEF(nonce_i, MAM_MSS_SKN_SIZE); 28 | mam_sponge_init(&sponge); 29 | mam_wots_reset(&wots); 30 | 31 | MAM_ASSERT(0 <= i && i <= MAM_MSS_MAX_SKN(mss->height)); 32 | nonce_i = MAM_TRITS_INIT(nonce_i, MAM_MSS_SKN_SIZE); 33 | 34 | /* gen sk from current leaf index */ 35 | trits_put18(nonce_i, i); 36 | mam_wots_gen_sk5(&wots, mss->prng, mss->nonce1, mss->nonce2, mss->nonce3, mss->nonce4, nonce_i); 37 | /* gen pk & push hash */ 38 | mam_wots_gen_pk(&wots, pk); 39 | } 40 | 41 | retcode_t mam_mss_sign(mam_mss_t *mss, trits_t hash, trits_t sig) { 42 | mam_wots_t wots; 43 | mam_sponge_t sponge; 44 | MAM_ASSERT(trits_size(sig) == MAM_MSS_SIG_SIZE(mss->height)); 45 | 46 | if (mam_mss_remaining_sks(mss) == 0) { 47 | return RC_MAM_MSS_EXHAUSTED; 48 | } 49 | 50 | // Write both tree height and the sk index to the signature 51 | mam_mss_skn(mss, trits_take(sig, MAM_MSS_SKN_SIZE)); 52 | sig = trits_drop(sig, MAM_MSS_SKN_SIZE); 53 | 54 | mam_sponge_init(&sponge); 55 | mam_wots_reset(&wots); 56 | { 57 | // Generate the current (skn) secret key 58 | MAM_TRITS_DEF(nonce_i, MAM_MSS_SKN_SIZE); 59 | nonce_i = MAM_TRITS_INIT(nonce_i, MAM_MSS_SKN_SIZE); 60 | trits_put18(nonce_i, mss->skn); 61 | mam_wots_gen_sk5(&wots, mss->prng, mss->nonce1, mss->nonce2, mss->nonce3, mss->nonce4, nonce_i); 62 | } 63 | 64 | mam_wots_sign(&wots, hash, trits_take(sig, MAM_WOTS_SIGNATURE_SIZE)); 65 | sig = trits_drop(sig, MAM_WOTS_SIGNATURE_SIZE); 66 | 67 | mam_mss_auth_path(mss, mss->skn, sig); 68 | 69 | return RC_OK; 70 | } 71 | 72 | retcode_t mam_mss_sign_and_next(mam_mss_t *mss, trits_t hash, trits_t sig) { 73 | retcode_t ret; 74 | ERR_BIND_RETURN(mam_mss_sign(mss, hash, sig), ret); 75 | mam_mss_next(mss); 76 | return RC_OK; 77 | } 78 | 79 | void mam_mss_skn(mam_mss_t const *const mss, trits_t skn) { 80 | MAM_TRITS_DEF(trits, MAM_MSS_SKN_SIZE); 81 | trits = MAM_TRITS_INIT(trits, MAM_MSS_SKN_SIZE); 82 | 83 | MAM_ASSERT(trits_size(skn) == MAM_MSS_SKN_SIZE); 84 | 85 | trits_put6(trits, mss->height); 86 | trits_copy(trits_take(trits, MAM_MSS_SKN_TREE_DEPTH_SIZE), trits_take(skn, MAM_MSS_SKN_TREE_DEPTH_SIZE)); 87 | 88 | trits_put18(trits, mss->skn); 89 | trits_copy(trits_take(trits, MAM_MSS_SKN_KEY_NUMBER_SIZE), trits_drop(skn, MAM_MSS_SKN_TREE_DEPTH_SIZE)); 90 | } 91 | 92 | bool mam_mss_verify(mam_spongos_t *mt_spongos, trits_t hash, trits_t sig, trits_t pk) { 93 | mss_mt_height_t height; 94 | mss_mt_idx_t skn; 95 | MAM_TRITS_DEF(calculated_pk, MAM_MSS_MT_HASH_SIZE); 96 | calculated_pk = MAM_TRITS_INIT(calculated_pk, MAM_MSS_MT_HASH_SIZE); 97 | 98 | MAM_ASSERT(trits_size(pk) == MAM_MSS_PK_SIZE); 99 | 100 | if (trits_size(sig) < MAM_MSS_SIG_SIZE(0)) return false; 101 | 102 | if (!mss_parse_skn(&height, &skn, trits_take(sig, MAM_MSS_SKN_SIZE))) { 103 | return false; 104 | } 105 | 106 | sig = trits_drop(sig, MAM_MSS_SKN_SIZE); 107 | if (trits_size(sig) != (size_t)(MAM_MSS_SIG_SIZE(height) - MAM_MSS_SKN_SIZE)) return false; 108 | 109 | mam_wots_recover(hash, trits_take(sig, MAM_WOTS_SIGNATURE_SIZE), calculated_pk); 110 | sig = trits_drop(sig, MAM_WOTS_SIGNATURE_SIZE); 111 | 112 | mss_fold_auth_path(mt_spongos, skn, sig, calculated_pk); 113 | 114 | return trits_cmp_eq(calculated_pk, pk); 115 | } 116 | 117 | bool mss_parse_skn(mss_mt_height_t *height, mss_mt_idx_t *skn, trits_t trits) { 118 | MAM_TRITS_DEF(ts, MAM_MSS_SKN_SIZE); 119 | ts = MAM_TRITS_INIT(ts, MAM_MSS_SKN_SIZE); 120 | 121 | MAM_ASSERT(MAM_MSS_SKN_SIZE == trits_size(trits)); 122 | 123 | trits_set_zero(ts); 124 | 125 | trits_copy(trits_take(trits, MAM_MSS_SKN_TREE_DEPTH_SIZE), trits_take(ts, MAM_MSS_SKN_TREE_DEPTH_SIZE)); 126 | *height = trits_get6(ts); 127 | 128 | trits_copy(trits_drop(trits, MAM_MSS_SKN_TREE_DEPTH_SIZE), trits_take(ts, MAM_MSS_SKN_KEY_NUMBER_SIZE)); 129 | *skn = trits_get18(ts); 130 | 131 | if (*height > MAM_MSS_MAX_D || *skn > MAM_MSS_MAX_SKN(*height)) return 0; 132 | 133 | return 1; 134 | } 135 | 136 | /** 137 | * Calculate the mss root (pk) 138 | * 139 | * @param spongos [in] The spongos that is used to hash nodes on the tree 140 | * @param skn [in] number of WOTS instance (current pk index), in traversal mode 141 | * @param auth_path [in] authentication path - leaf to root 142 | * @param pk [in] recovered WOTS pk / start hash value [out] recovered MT root 143 | * 144 | * @return void 145 | */ 146 | 147 | void mss_fold_auth_path(mam_spongos_t *spongos, mss_mt_idx_t skn, trits_t auth_path, trits_t pk) { 148 | trits_t hashes[2]; 149 | 150 | for (; !trits_is_empty(auth_path); skn /= 2, auth_path = trits_drop(auth_path, MAM_MSS_MT_HASH_SIZE)) { 151 | hashes[skn % 2] = pk; 152 | hashes[1 - (skn % 2)] = trits_take(auth_path, MAM_MSS_MT_HASH_SIZE); 153 | mss_hash2(spongos, hashes, pk); 154 | } 155 | } 156 | 157 | size_t mam_mss_remaining_sks(mam_mss_t const *const mss) { 158 | if (mss->skn > MAM_MSS_MAX_SKN(mss->height)) { 159 | return 0; 160 | } 161 | 162 | return MAM_MSS_MAX_SKN(mss->height) - mss->skn + 1; 163 | } 164 | 165 | size_t mam_mss_serialized_size(mam_mss_t const *const mss) { 166 | return MAM_MSS_SKN_TREE_DEPTH_SIZE + MAM_MSS_SKN_KEY_NUMBER_SIZE + mss_mt_serialized_size(mss) + MAM_MSS_PK_SIZE; 167 | } 168 | 169 | void mam_mss_serialize(mam_mss_t const *const mss, trits_t *const buffer) { 170 | MAM_ASSERT(trits_size(*buffer) >= mam_mss_serialized_size(mss)); 171 | 172 | mam_mss_skn(mss, trits_take(*buffer, MAM_MSS_SKN_SIZE)); 173 | trits_advance(buffer, MAM_MSS_SKN_SIZE); 174 | mss_mt_serialize(mss, buffer); 175 | pb3_encode_ntrytes(trits_from_rep(MAM_MSS_PK_SIZE, mss->root), buffer); 176 | } 177 | -------------------------------------------------------------------------------- /mam/mss/mss_traversal.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 IOTA Stiftung 3 | * https://github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by [ITSec Lab] 6 | * 7 | * Refer to the LICENSE file for licensing information 8 | */ 9 | 10 | /** 11 | * @ingroup mam 12 | * 13 | * @{ 14 | * 15 | * @file 16 | * @brief 17 | * 18 | */ 19 | #ifndef __MAM_MSS_MSS_TRAVERSAL_H__ 20 | #define __MAM_MSS_MSS_TRAVERSAL_H__ 21 | 22 | #include "common/errors.h" 23 | #include "mam/defs.h" 24 | #include "mam/mss/mss_common.h" 25 | #include "mam/prng/prng.h" 26 | #include "mam/sponge/spongos.h" 27 | #include "mam/trits/trits.h" 28 | #include "mam/wots/wots.h" 29 | 30 | #ifdef __cplusplus 31 | extern "C" { 32 | #endif 33 | 34 | /*! \brief Node info, specifies position of the node in the MT. 35 | \note Corresponding hash-value is stored externally. */ 36 | typedef struct mss_mt_node_s { 37 | mss_mt_height_t height; /*!< Height. */ 38 | mss_mt_idx_t level_idx; /*!< Level index. */ 39 | } mss_mt_node_t; 40 | /*! \brief Number of auxiliary MT nodes used by tree-traversal algorithm */ 41 | #define MAM_MSS_MT_NODES(d) ((d) * ((d) + 1) / 2) 42 | 43 | /*! \brief Stack info. 44 | \note Stack nodes are stored externally. */ 45 | typedef struct mss_mt_stack_s { 46 | mss_mt_height_t height; /*!< Height. */ 47 | mss_mt_idx_t level_idx; /*!< Level index. */ 48 | size_t size; /*!< Size of stack. */ 49 | } mss_mt_stack_t; 50 | /*! \brief Number of auxiliary stacks used by tree-traversal algorithm */ 51 | #define MAM_MSS_MT_STACKS(d) (d) 52 | #define MAM_MSS_MT_STACK_CAPACITY(d) ((d) + 1) 53 | 54 | #define MAM_MSS_HASH_IDX(i) (MAM_MSS_MT_HASH_SIZE * (i)) 55 | /*! \brief Memory for hash-values. TODO: Add 1 extra hash for mss_gen. */ 56 | #define MAM_MSS_MT_HASH_WORDS(d, i) MAM_MSS_HASH_IDX(MAM_MSS_MT_NODES(d) + (i)) 57 | #define MAM_MSS_MT_AUTH_WORDS(d) MAM_MSS_HASH_IDX(d) 58 | 59 | #define MAM_MSS_MT_MAX_STORED_SIZE(d) ((d) * ((d) + 3) / 2 * MAM_MSS_MT_HASH_SIZE) 60 | #define MAM_MSS_MAX_STORED_SIZE(d) (4 + 14 + MAM_MSS_MT_MAX_STORED_SIZE(d)) 61 | 62 | /*! \brief MSS interface used to generate public key and sign. */ 63 | typedef struct mam_mss_s { 64 | mss_mt_height_t height; /*!< Merkle tree height. */ 65 | mss_mt_idx_t skn; /*!< Current WOTS private key number. */ 66 | mam_prng_t *prng; /*!< PRNG interface used to generate WOTS private keys. */ 67 | trit_t *auth_path; /*!< Current authentication path; `d` hash values. */ 68 | trit_t *nodes_hashes; /*!< Buffer storing hash-values of auxiliary nodes; MAM_MSS_MT_NODES(d) hash-values in total. */ 69 | mss_mt_node_t *nodes; /*height = D; 90 | m->ap = alloc_words(D * MAM_MSS_MT_HASH_SIZE); 91 | m->hs = alloc_words(total_nodes * MAM_MSS_MT_HASH_SIZE); 92 | m->nodes = alloc_nodes(total_nodes); 93 | m->stacks = alloc_stacks(D); 94 | ``` 95 | */ 96 | 97 | #ifdef __cplusplus 98 | } 99 | #endif 100 | 101 | #endif // __MAM_MSS_MSS_TRAVERSAL_H__ 102 | -------------------------------------------------------------------------------- /mam/mss/tests/BUILD: -------------------------------------------------------------------------------- 1 | cc_test( 2 | name = "test_mss_classic", 3 | timeout = "eternal", 4 | srcs = ["test_mss.c"], 5 | deps = [ 6 | "//mam/mss:mss_classic", 7 | "@org_iota_common//utils/handles:rand", 8 | "@unity", 9 | ], 10 | ) 11 | 12 | cc_test( 13 | name = "test_mss_traversal", 14 | timeout = "eternal", 15 | srcs = ["test_mss.c"], 16 | deps = [ 17 | "//mam/mss:mss_traversal", 18 | "@org_iota_common//utils/handles:rand", 19 | "@unity", 20 | ], 21 | ) 22 | -------------------------------------------------------------------------------- /mam/mss/tests/test_mss.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https://github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by [ITSec Lab] 6 | * 7 | * Refer to the LICENSE file for licensing information 8 | */ 9 | 10 | #include 11 | 12 | #include "mam/mss/mss.h" 13 | #include "utils/handles/rand.h" 14 | 15 | static void mss_store_test(mam_mss_t *mss1, mam_mss_t *mss2, mam_prng_t *prng, mss_mt_height_t max_height) { 16 | mss_mt_height_t curr_height; 17 | MAM_TRITS_DEF(key, MAM_PRNG_SECRET_KEY_SIZE); 18 | MAM_TRITS_DEF(nonce, 24); 19 | MAM_TRITS_DEF(hash, MAM_MSS_HASH_SIZE); 20 | MAM_TRITS_DEF(sig_, MAM_MSS_SIG_SIZE(5)); 21 | MAM_TRITS_DEF(sig2_, MAM_MSS_SIG_SIZE(5)); 22 | MAM_TRITS_DEF(store_, MAM_MSS_MAX_STORED_SIZE(5)); 23 | trits_t sig, sig2, store; 24 | size_t sks = 0; 25 | 26 | key = MAM_TRITS_INIT(key, MAM_PRNG_SECRET_KEY_SIZE); 27 | nonce = MAM_TRITS_INIT(nonce, 24); 28 | hash = MAM_TRITS_INIT(hash, MAM_MSS_HASH_SIZE); 29 | sig_ = MAM_TRITS_INIT(sig_, MAM_MSS_SIG_SIZE(5)); 30 | sig2_ = MAM_TRITS_INIT(sig2_, MAM_MSS_SIG_SIZE(5)); 31 | store_ = MAM_TRITS_INIT(store_, MAM_MSS_MAX_STORED_SIZE(5)); 32 | 33 | trits_from_str(key, "ABCNOABCNKOZWYKOZWYSDF9SDF9YSDF9QABCNKOZWYSDF9ABCNKOZWSDF9CABCABCNKOZWYNKOZWYSDF9"); 34 | mam_prng_init(prng, key); 35 | trits_set_zero(nonce); 36 | trits_set_zero(hash); 37 | trits_from_str(hash, "ABCNKOZWYSDF9OABCNKOZWYSDF9ABCNKOZWYSDF9QABCNKOZWYSDF9ABCNKOZWYSDF9CABCNKOZWYSDF9"); 38 | 39 | for (curr_height = 0; curr_height <= max_height; ++curr_height) { 40 | sks = 0; 41 | sig = trits_take(sig_, MAM_MSS_SIG_SIZE(curr_height)); 42 | sig2 = trits_take(sig2_, MAM_MSS_SIG_SIZE(curr_height)); 43 | 44 | TEST_ASSERT(mam_mss_create(mss1, curr_height) == RC_OK); 45 | mam_mss_init(mss1, prng, curr_height, nonce, trits_null(), trits_null(), trits_null()); 46 | TEST_ASSERT(mam_mss_create(mss2, curr_height) == RC_OK); 47 | mam_mss_init(mss2, prng, curr_height, nonce, trits_null(), trits_null(), trits_null()); 48 | mam_mss_gen(mss1); 49 | 50 | while (mam_mss_remaining_sks(mss1) > 0) { 51 | store = trits_take(store_, mam_mss_serialized_size(mss1)); 52 | mam_mss_serialize(mss1, &store); 53 | store = trits_pickup_all(store); 54 | TEST_ASSERT(mam_mss_deserialize(&store, mss2) == RC_OK); 55 | 56 | TEST_ASSERT(mam_mss_sign_and_next(mss1, hash, sig) == RC_OK); 57 | TEST_ASSERT(mam_mss_sign_and_next(mss2, hash, sig2) == RC_OK); 58 | TEST_ASSERT_TRUE(trits_cmp_eq(sig, sig2)); 59 | sks++; 60 | } 61 | 62 | TEST_ASSERT_EQUAL_INT(sks, 1 << curr_height); 63 | TEST_ASSERT_EQUAL_INT(mam_mss_remaining_sks(mss1), 0); 64 | TEST_ASSERT(mam_mss_sign_and_next(mss1, hash, sig) == RC_MAM_MSS_EXHAUSTED); 65 | TEST_ASSERT(mam_mss_sign_and_next(mss2, hash, sig2) == RC_MAM_MSS_EXHAUSTED); 66 | 67 | mam_mss_destroy(mss1); 68 | mam_mss_destroy(mss2); 69 | } 70 | } 71 | 72 | static void mss_test(mam_mss_t *mss, mam_prng_t *prng, mam_spongos_t *spongos, mss_mt_height_t max_height) { 73 | MAM_TRITS_DEF(key, MAM_PRNG_SECRET_KEY_SIZE); 74 | mss_mt_height_t curr_height; 75 | MAM_TRITS_DEF(nonce, 24); 76 | MAM_TRITS_DEF(hash, MAM_MSS_HASH_SIZE); 77 | trits_t sig_; 78 | size_t sks = 0; 79 | 80 | key = MAM_TRITS_INIT(key, MAM_PRNG_SECRET_KEY_SIZE); 81 | nonce = MAM_TRITS_INIT(nonce, 24); 82 | hash = MAM_TRITS_INIT(hash, MAM_MSS_HASH_SIZE); 83 | sig_ = trits_alloc(MAM_MSS_SIG_SIZE(max_height)); 84 | 85 | trits_from_str(key, 86 | "ABCNOABCNKOZWYKOZWYSDF9SDF9" 87 | "YSDF9QABCNKOZWYSDF9ABCNKOZW" 88 | "SDF9CABCABCNKOZWYNKOZWYSDF9"); 89 | mam_prng_init(prng, key); 90 | trits_set_zero(nonce); 91 | trits_set_zero(hash); 92 | trits_from_str(hash, 93 | "ABCNKOZWYSDF9OABCNKOZWYSDF9" 94 | "ABCNKOZWYSDF9QABCNKOZWYSDF9" 95 | "ABCNKOZWYSDF9CABCNKOZWYSDF9"); 96 | 97 | for (curr_height = 1; curr_height <= max_height; ++curr_height) { 98 | sks = 0; 99 | trits_t sig = trits_take(sig_, MAM_MSS_SIG_SIZE(curr_height)); 100 | trits_t sig_skn = trits_take(sig, MAM_MSS_SKN_SIZE); 101 | trits_t sig_wots = trits_take(trits_drop(sig, MAM_MSS_SKN_SIZE), MAM_WOTS_SIGNATURE_SIZE); 102 | trits_t sig_apath = trits_drop(sig, MAM_MSS_SKN_SIZE + MAM_WOTS_SIGNATURE_SIZE); 103 | 104 | TEST_ASSERT(mam_mss_create(mss, curr_height) == RC_OK); 105 | mam_mss_init(mss, prng, curr_height, nonce, trits_null(), trits_null(), trits_null()); 106 | mam_mss_gen(mss); 107 | 108 | trits_t pk = trits_from_rep(MAM_MSS_PK_SIZE, mss->root); 109 | 110 | while (mam_mss_remaining_sks(mss) > 0) { 111 | TEST_ASSERT(mam_mss_sign_and_next(mss, hash, sig) == RC_OK); 112 | 113 | TEST_ASSERT_TRUE(mam_mss_verify(spongos, hash, sig, pk)); 114 | 115 | /* H is ignored, makes no sense to modify and check */ 116 | trits_put1(hash, trit_add(trits_get1(hash), 1)); 117 | TEST_ASSERT_FALSE(mam_mss_verify(spongos, hash, sig, pk)); 118 | trits_put1(hash, trit_sub(trits_get1(hash), 1)); 119 | 120 | trits_put1(sig_skn, trit_add(trits_get1(sig_skn), 1)); 121 | TEST_ASSERT_FALSE(mam_mss_verify(spongos, hash, sig, pk)); 122 | trits_put1(sig_skn, trit_sub(trits_get1(sig_skn), 1)); 123 | 124 | /* WOTS sig is ignored, makes no sense to modify and check */ 125 | trits_put1(sig_wots, trit_add(trits_get1(sig_wots), 1)); 126 | TEST_ASSERT_FALSE(mam_mss_verify(spongos, hash, sig, pk)); 127 | trits_put1(sig_wots, trit_sub(trits_get1(sig_wots), 1)); 128 | 129 | if (!trits_is_empty(sig_apath)) { 130 | trits_put1(sig_apath, trit_add(trits_get1(sig_apath), 1)); 131 | TEST_ASSERT_FALSE(mam_mss_verify(spongos, hash, sig, pk)); 132 | trits_put1(sig_apath, trit_sub(trits_get1(sig_apath), 1)); 133 | } 134 | 135 | TEST_ASSERT_FALSE(mam_mss_verify(spongos, hash, trits_take(sig, trits_size(sig) - 1), pk)); 136 | 137 | trits_put1(pk, trit_add(trits_get1(pk), 1)); 138 | TEST_ASSERT_FALSE(mam_mss_verify(spongos, hash, sig, pk)); 139 | trits_put1(pk, trit_sub(trits_get1(pk), 1)); 140 | sks++; 141 | } 142 | 143 | TEST_ASSERT_EQUAL_INT(sks, 1 << curr_height); 144 | TEST_ASSERT_EQUAL_INT(mam_mss_remaining_sks(mss), 0); 145 | TEST_ASSERT(mam_mss_sign_and_next(mss, hash, sig) == RC_MAM_MSS_EXHAUSTED); 146 | 147 | mam_mss_destroy(mss); 148 | } 149 | 150 | trits_free(sig_); 151 | } 152 | 153 | static void mss_meta_test(void) { 154 | mam_spongos_t spongos; 155 | mam_prng_t prng; 156 | mam_mss_t mss1; 157 | mam_mss_t mss2; 158 | 159 | mam_spongos_init(&spongos); 160 | 161 | mss_test(&mss1, &prng, &spongos, 3); 162 | mss_store_test(&mss1, &mss2, &prng, 2); 163 | } 164 | 165 | int main(void) { 166 | UNITY_BEGIN(); 167 | 168 | RUN_TEST(mss_meta_test); 169 | 170 | return UNITY_END(); 171 | } 172 | -------------------------------------------------------------------------------- /mam/ntru/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//visibility:public"]) 2 | 3 | load("@org_iota_common//utils/containers:typed_container_generator.bzl", "typed_container_generate") 4 | 5 | config_setting( 6 | name = "mred_binary", 7 | values = {"define": "mred_binary=1"}, 8 | ) 9 | 10 | config_setting( 11 | name = "no_mred_binary", 12 | values = {"define": "mred_binary=0"}, 13 | ) 14 | 15 | cc_library( 16 | name = "ntru_types_hdr", 17 | hdrs = ["ntru_types.h"], 18 | deps = [ 19 | ":poly", 20 | "//mam:defs", 21 | ], 22 | ) 23 | 24 | cc_library( 25 | name = "ntru", 26 | srcs = ["ntru.c"], 27 | hdrs = ["ntru.h"], 28 | deps = [ 29 | ":mam_ntru_pk_t_set", 30 | ":mam_ntru_sk_t_set", 31 | ":ntru_types_hdr", 32 | "//mam/prng", 33 | "//mam/sponge:spongos", 34 | "@org_iota_common//utils:memset_safe", 35 | ], 36 | ) 37 | 38 | typed_container_generate( 39 | additional_deps = ":ntru_types_hdr", 40 | additional_include_path = "mam/ntru/ntru_types.h", 41 | container_type = "set", 42 | parent_directory = "mam/ntru", 43 | value_type = "mam_ntru_pk_t", 44 | ) 45 | 46 | typed_container_generate( 47 | additional_deps = ":ntru_types_hdr", 48 | additional_include_path = "mam/ntru/ntru_types.h", 49 | container_type = "set", 50 | parent_directory = "mam/ntru", 51 | value_type = "mam_ntru_sk_t", 52 | ) 53 | 54 | cc_library( 55 | name = "poly", 56 | deps = 57 | select({ 58 | ":mred_binary": [":poly_mred_binary"], 59 | ":no_mred_binary": [":poly_no_mred_binary"], 60 | "//conditions:default": [":poly_no_mred_binary"], 61 | }), 62 | ) 63 | 64 | cc_library( 65 | name = "poly_mred_binary", 66 | srcs = ["poly.c"], 67 | hdrs = [ 68 | "poly.h", 69 | "poly_param.h", 70 | ], 71 | defines = ["MAM_POLY_MRED_BINARY"], 72 | deps = [ 73 | "//mam:defs", 74 | "//mam/trits", 75 | ], 76 | ) 77 | 78 | cc_library( 79 | name = "poly_no_mred_binary", 80 | srcs = ["poly.c"], 81 | hdrs = [ 82 | "poly.h", 83 | "poly_param.h", 84 | ], 85 | deps = [ 86 | "//mam:defs", 87 | "//mam/trits", 88 | ], 89 | ) 90 | -------------------------------------------------------------------------------- /mam/ntru/ntru.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https://github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by 6 | * [ITSec Lab] 7 | * 8 | * Refer to the LICENSE file for licensing information 9 | */ 10 | 11 | /** 12 | * @ingroup mam 13 | * 14 | * @{ 15 | * 16 | * @file 17 | * @brief 18 | * 19 | */ 20 | #ifndef __MAM_NTRU_NTRU_H__ 21 | #define __MAM_NTRU_NTRU_H__ 22 | 23 | #include "mam/defs.h" 24 | #include "mam/ntru/mam_ntru_pk_t_set.h" 25 | #include "mam/ntru/mam_ntru_sk_t_set.h" 26 | #include "mam/ntru/ntru_types.h" 27 | #include "mam/prng/prng.h" 28 | #include "mam/sponge/spongos.h" 29 | #include "mam/trits/trits.h" 30 | 31 | #ifdef __cplusplus 32 | extern "C" { 33 | #endif 34 | 35 | /* 36 | * NTRU public key 37 | */ 38 | 39 | /** 40 | * Gets a NTRU public key id trits 41 | * 42 | * @param ntru_pk The NTRU public key 43 | * 44 | * @return the NTRU public key id trits 45 | */ 46 | static inline trits_t mam_ntru_pk_id(mam_ntru_pk_t const *const ntru_pk) { 47 | return trits_from_rep(MAM_NTRU_ID_SIZE, ntru_pk->key); 48 | } 49 | 50 | /** 51 | * Gets a NTRU public key trits 52 | * 53 | * @param ntru_pk The NTRU public key 54 | * 55 | * @return the NTRU public key trits 56 | */ 57 | static inline trits_t mam_ntru_pk_key(mam_ntru_pk_t const *const ntru_pk) { 58 | return trits_from_rep(MAM_NTRU_PK_SIZE, ntru_pk->key); 59 | } 60 | 61 | /** 62 | * NTRU encryption of a session key 63 | * 64 | * @param ntru_pk A NTRU public key 65 | * @param prng A PRNG interface 66 | * @param spongos A spongos interface 67 | * @param nonce A nonce 68 | * @param session_key A session symmetric key to be encrypted 69 | * @param encrypted_session_key The encrypted session key 70 | * 71 | * @return a status code 72 | */ 73 | retcode_t ntru_pk_encr(mam_ntru_pk_t const *const ntru_pk, mam_prng_t const *const prng, mam_spongos_t *const spongos, 74 | trits_t const nonce, trits_t const session_key, trits_t encrypted_session_key); 75 | 76 | /** 77 | * Gets the size of a serialized set of NTRU public keys 78 | * 79 | * @param ntru_pks The set of NTRU public keys 80 | * 81 | * @return the serialized size 82 | */ 83 | size_t mam_ntru_pks_serialized_size(mam_ntru_pk_t_set_t const ntru_pks); 84 | 85 | /** 86 | * Serializes a set of NTRU public keys into a trits buffer 87 | * 88 | * @param ntru_pks The set of NTRU public keys 89 | * @param trits The trits buffer to serialize into 90 | * 91 | * @return a status code 92 | */ 93 | retcode_t mam_ntru_pks_serialize(mam_ntru_pk_t_set_t const ntru_pks, trits_t *const trits); 94 | 95 | /** 96 | * Deserializes a set of NTRU public keys from a trits buffer 97 | * 98 | * @param trits The trits buffer to deserialize from 99 | * @param ntru_pks The set of NTRU public keys 100 | * 101 | * @return a status code 102 | */ 103 | retcode_t mam_ntru_pks_deserialize(trits_t *const trits, mam_ntru_pk_t_set_t *const ntru_pks); 104 | 105 | /* 106 | * NTRU secret key 107 | */ 108 | 109 | /** 110 | * Gets a NTRU secret key's public key id trits 111 | * 112 | * @param ntru_sk The NTRU secret key 113 | * 114 | * @return the NTRU secret key's public key id trits 115 | */ 116 | static inline trits_t ntru_sk_pk_id(mam_ntru_sk_t const *const ntru_sk) { 117 | return trits_from_rep(MAM_NTRU_ID_SIZE, ntru_sk->public_key.key); 118 | } 119 | 120 | /** 121 | * Gets a NTRU secret key's public key trits 122 | * 123 | * @param ntru_sk The NTRU secret key 124 | * 125 | * @return the NTRU secret key's public key trits 126 | */ 127 | static inline trits_t ntru_sk_pk_key(mam_ntru_sk_t const *const ntru_sk) { 128 | return trits_from_rep(MAM_NTRU_PK_SIZE, ntru_sk->public_key.key); 129 | } 130 | 131 | /** 132 | * Gets a NTRU secret key trits 133 | * 134 | * @param ntru_sk The NTRU secret key 135 | * 136 | * @return the NTRU secret key trits 137 | */ 138 | static inline trits_t ntru_sk_key(mam_ntru_sk_t const *const ntru_sk) { 139 | return trits_from_rep(MAM_NTRU_SK_SIZE, ntru_sk->secret_key); 140 | } 141 | 142 | /** 143 | * Safely resets a NTRU secret key by clearing its secret part 144 | * 145 | * @param ntru_sk The NTRU secret key 146 | * 147 | * @return a status code 148 | */ 149 | retcode_t ntru_sk_reset(mam_ntru_sk_t *const ntru_sk); 150 | 151 | /** 152 | * Generates a NTRU secret key 153 | * 154 | * @param ntru_sk The NTRU secret key 155 | * @param prng A PRNG interface 156 | * @param nonce A nonce 157 | */ 158 | void ntru_sk_gen(mam_ntru_sk_t const *const ntru_sk, mam_prng_t const *const prng, trits_t const nonce); 159 | 160 | /** 161 | * NTRU decryption of an encrypted session key 162 | * 163 | * @param ntru_sk A NTRU secret key 164 | * @param spongos A spongos interface 165 | * @param encrypted_session_key An encrypted session key 166 | * @param session_key The decrypted session symmetric key 167 | * 168 | * @return true if decryption succeeded,false otherwise 169 | */ 170 | bool ntru_sk_decr(mam_ntru_sk_t const *const ntru_sk, mam_spongos_t *const spongos, trits_t const encrypted_session_key, 171 | trits_t session_key); 172 | 173 | /** 174 | * Loads the internal representation of a NTRU secret key 175 | * 176 | * @param ntru_sk A NTRU secret key 177 | */ 178 | void ntru_sk_load(mam_ntru_sk_t *const ntru_sk); 179 | 180 | /** 181 | * Safely destroys a set of NTRU secret keys by clearing their secret part and 182 | * releasing memory 183 | * 184 | * @param ntru_pks The set of NTRU public keys 185 | */ 186 | void mam_ntru_sks_destroy(mam_ntru_sk_t_set_t *const ntru_sks); 187 | 188 | /** 189 | * Gets the size of a serialized set of NTRU secret keys 190 | * 191 | * @param ntru_sks The set of NTRU secret keys 192 | * 193 | * @return the serialized size 194 | */ 195 | size_t mam_ntru_sks_serialized_size(mam_ntru_sk_t_set_t const ntru_sks); 196 | 197 | /** 198 | * Serializes a set of NTRU secret keys into a trits buffer 199 | * 200 | * @param ntru_sks The set of NTRU secret keys 201 | * @param trits The trits buffer to serialize into 202 | * 203 | * @return a status code 204 | */ 205 | retcode_t mam_ntru_sks_serialize(mam_ntru_sk_t_set_t const ntru_sks, trits_t *const trits); 206 | 207 | /** 208 | * Deserializes a set of NTRU secret keys from a trits buffer 209 | * 210 | * @param trits The trits buffer to deserialize from 211 | * @param ntru_sks The set of NTRU secret keys 212 | * 213 | * @return a status code 214 | */ 215 | retcode_t mam_ntru_sks_deserialize(trits_t *const trits, mam_ntru_sk_t_set_t *const ntru_sks); 216 | 217 | #ifdef __cplusplus 218 | } 219 | #endif 220 | 221 | #endif // __MAM_NTRU_NTRU_H__ 222 | 223 | /** @} */ 224 | -------------------------------------------------------------------------------- /mam/ntru/ntru_types.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https://github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by 6 | * [ITSec Lab] 7 | * 8 | * Refer to the LICENSE file for licensing information 9 | */ 10 | 11 | /** 12 | * @ingroup mam 13 | * 14 | * @{ 15 | * 16 | * @file 17 | * @brief 18 | * 19 | */ 20 | #ifndef __MAM_NTRU_NTRU_TYPES_H__ 21 | #define __MAM_NTRU_NTRU_TYPES_H__ 22 | 23 | #include "mam/defs.h" 24 | #include "mam/ntru/poly.h" 25 | 26 | // NTRU id size 27 | #define MAM_NTRU_ID_SIZE 81 28 | // NTRU public key size 29 | #define MAM_NTRU_PK_SIZE 9216 30 | // NTRU secret key size 31 | #define MAM_NTRU_SK_SIZE 1024 32 | // NTRU session symmetric key size 33 | #define MAM_NTRU_KEY_SIZE MAM_SPONGE_KEY_SIZE 34 | // NTRU encrypted key size 35 | #define MAM_NTRU_EKEY_SIZE 9216 36 | 37 | /** 38 | * The NTRU layer supports an NTRU-style public key encryption scheme 39 | * Using NTRU a sender can encrypt session keys with a public key of a recipient 40 | * The secret key must be kept in secret 41 | * The corresponding public key, on the contrary, is publicly announced 42 | */ 43 | 44 | // Receiver's NTRU public key 45 | typedef struct mam_ntru_pk_s { 46 | trit_t key[MAM_NTRU_PK_SIZE]; 47 | } mam_ntru_pk_t; 48 | 49 | typedef struct mam_ntru_pk_t_set_entry_s mam_ntru_pk_t_set_entry_t; 50 | typedef mam_ntru_pk_t_set_entry_t* mam_ntru_pk_t_set_t; 51 | 52 | // Sender's NTRU secret key 53 | typedef struct mam_ntru_sk_s { 54 | // Associated public key 55 | mam_ntru_pk_t public_key; 56 | // Secret key - small coefficients of polynomial f 57 | trit_t secret_key[MAM_NTRU_SK_SIZE]; 58 | // Internal representation of a private key: NTT(1+3f) 59 | poly_t f; 60 | } mam_ntru_sk_t; 61 | 62 | typedef struct mam_ntru_sk_t_set_entry_s mam_ntru_sk_t_set_entry_t; 63 | typedef mam_ntru_sk_t_set_entry_t* mam_ntru_sk_t_set_t; 64 | 65 | #endif // __MAM_NTRU_NTRU_TYPES_H__ 66 | 67 | /** @} */ 68 | -------------------------------------------------------------------------------- /mam/ntru/poly.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https://github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by 6 | * [ITSec Lab] 7 | * 8 | * Refer to the LICENSE file for licensing information 9 | */ 10 | 11 | #include "mam/ntru/poly.h" 12 | #include "mam/ntru/poly_param.h" 13 | 14 | /* 15 | * Public functions 16 | */ 17 | 18 | #if defined(MAM_POLY_MRED_BINARY) 19 | poly_coeff_t poly_coeff_mredd(poly_dcoeff_t m) { 20 | poly_coeff_t s = m; 21 | 22 | s = (poly_coeff_t)m * MAM_POLY_MRED_Q_INV; 23 | /*s = (s << 12) + (s << 13) - s;*/ 24 | 25 | m = m + s * MAM_POLY_Q; 26 | /*m = m + (s << 12) + (s << 13) + s;*/ 27 | 28 | /* s := m div R */ 29 | s = m >> MAM_POLY_MRED_R_LOG; 30 | s = (s < MAM_POLY_Q) ? s : (s - MAM_POLY_Q); 31 | MAM_ASSERT(s < MAM_POLY_Q); 32 | 33 | return s; 34 | } 35 | #endif 36 | 37 | void poly_ntt(poly_t const f, poly_t t) { 38 | poly_t u; 39 | poly_coeff_t c, d; 40 | size_t r; 41 | 42 | for (size_t i = 0; i < MAM_POLY_N; ++i) { 43 | u[poly_idx_rev[i]] = poly_coeff_mul(poly_gamma_exp[i], f[i]); 44 | } 45 | 46 | for (size_t i = MAM_POLY_N_LOG; i--;) { 47 | for (size_t j = 0; j < MAM_POLY_N / 2; ++j) { 48 | r = j & ~(((size_t)1 << i) - 1); 49 | /*r = j - (j % (1 << i));*/ 50 | c = u[j + j]; 51 | d = poly_coeff_mul(u[j + j + 1], poly_gamma_exp[r + r]); 52 | t[j] = poly_coeff_add(c, d); 53 | t[j + MAM_POLY_N / 2] = poly_coeff_sub(c, d); 54 | } 55 | for (size_t j = 0; j < MAM_POLY_N; ++j) { 56 | u[j] = t[j]; 57 | } 58 | } 59 | } 60 | 61 | void poly_intt(poly_t const t, poly_t f) { 62 | poly_t u; 63 | poly_coeff_t c, d; 64 | size_t r; 65 | 66 | for (size_t i = 0; i < MAM_POLY_N; ++i) { 67 | u[poly_idx_rev[i]] = t[i]; 68 | } 69 | 70 | for (size_t i = MAM_POLY_N_LOG; i--;) { 71 | for (size_t j = 0; j < MAM_POLY_N / 2; ++j) { 72 | r = j & ~(((size_t)1 << i) - 1); 73 | /*r = j - (j % (1 << i));*/ 74 | c = u[j + j]; 75 | d = poly_coeff_mul(u[j + j + 1], poly_gamma_exp[2 * MAM_POLY_N - (r + r)]); 76 | f[j] = poly_coeff_add(c, d); 77 | f[j + MAM_POLY_N / 2] = poly_coeff_sub(c, d); 78 | } 79 | for (size_t j = 0; j < MAM_POLY_N; ++j) { 80 | u[j] = f[j]; 81 | } 82 | } 83 | 84 | for (size_t i = 0; i < MAM_POLY_N; ++i) { 85 | /* TODO: precomp γ⁻ⁱn⁻¹? */ 86 | c = poly_coeff_mul(MAM_POLY_COEFF_N_INV, poly_gamma_exp[2 * MAM_POLY_N - i]); 87 | f[i] = poly_coeff_mul(c, f[i]); 88 | } 89 | } 90 | 91 | void poly_round_to_trits(poly_t const f, trits_t t) { 92 | trint9_t c; 93 | MAM_ASSERT(trits_size(t) == MAM_POLY_N); 94 | 95 | for (size_t i = 0; i != MAM_POLY_N; ++i, t = trits_drop(t, 1)) { 96 | c = poly_coeff_to_trint9(f[i]); 97 | c = MAM_MODS(c, 27 * 27 * 27, 3); 98 | trits_put1(t, (trit_t)c); 99 | } 100 | } 101 | 102 | bool poly_from_trits(poly_t f, trits_t t) { 103 | size_t i; 104 | trint9_t c; 105 | MAM_ASSERT(trits_size(t) == 9 * MAM_POLY_N); 106 | 107 | for (i = 0; i < MAM_POLY_N; ++i, t = trits_drop(t, 9)) { 108 | c = trits_get9(t); 109 | if ((c < -((MAM_POLY_Q - 1) / 2)) || (((MAM_POLY_Q - 1) / 2) < c)) { 110 | break; 111 | } 112 | f[i] = poly_coeff_from_trint9(c); 113 | } 114 | return (i == MAM_POLY_N) ? 1 : 0; 115 | } 116 | 117 | poly_coeff_t poly_coeff_from_trint9(trint9_t const t) { 118 | #if defined(MAM_POLY_MRED_BINARY) 119 | /* `c*R (mod q)` */ 120 | poly_dcoeff_t d; 121 | poly_coeff_t c; 122 | MAM_ASSERT(-(MAM_POLY_Q - 1) / 2 <= t && t <= (MAM_POLY_Q - 1) / 2); 123 | 124 | d = t < 0 ? (poly_dcoeff_t)t + MAM_POLY_Q : (poly_dcoeff_t)t; 125 | c = (d << MAM_POLY_MRED_R_LOG) % MAM_POLY_Q; 126 | 127 | return c; 128 | #else 129 | MAM_ASSERT(-(MAM_POLY_Q - 1) / 2 <= t && t <= (MAM_POLY_Q - 1) / 2); 130 | 131 | return (poly_coeff_t)t; 132 | #endif 133 | } 134 | 135 | trint9_t poly_coeff_to_trint9(poly_coeff_t c) { 136 | #if defined(MAM_POLY_MRED_BINARY) 137 | /* `c/R (mods q)` */ 138 | poly_dcoeff_t d = c; 139 | trint9_t t; 140 | 141 | d *= MAM_POLY_MRED_RI; 142 | c = d % (poly_coeff_t)MAM_POLY_Q; 143 | t = (MAM_POLY_Q - 1) / 2 < c ? (trint9_t)c - MAM_POLY_Q : c; 144 | 145 | return t; 146 | #else 147 | c = (MAM_POLY_Q - 1) / 2 < c ? c - MAM_POLY_Q : c; 148 | 149 | return c; 150 | #endif 151 | } 152 | 153 | poly_coeff_t poly_coeff_add(poly_coeff_t const a, poly_coeff_t const b) { 154 | #if defined(MAM_POLY_MRED_BINARY) 155 | /* u = a + b mod R */ 156 | poly_coeff_t c = a + b; 157 | 158 | c = c < MAM_POLY_Q ? c : c - MAM_POLY_Q; 159 | 160 | return c; 161 | #else 162 | /* `a+b` can overflow, so need double precision */ 163 | poly_dcoeff_t sum = (poly_dcoeff_t)a + b; 164 | 165 | if (sum < -((MAM_POLY_Q - 1) / 2)) 166 | sum += MAM_POLY_Q; 167 | else if (sum > ((MAM_POLY_Q - 1) / 2)) 168 | sum -= MAM_POLY_Q; 169 | 170 | return sum; 171 | #endif 172 | } 173 | 174 | poly_coeff_t poly_coeff_inv(poly_coeff_t const a) { 175 | poly_coeff_t e, t; 176 | 177 | MAM_ASSERT(MAM_POLY_Q == ((3 * (1 << 12)) + 1)); 178 | /* q-2 = 10111111111111b */ 179 | 180 | e = a; 181 | for (size_t i = 0; i < 11; ++i) { 182 | t = poly_coeff_mul(e, e); 183 | e = poly_coeff_mul(t, a); 184 | } 185 | 186 | t = poly_coeff_mul(e, a); 187 | t = poly_coeff_mul(t, t); 188 | e = poly_coeff_mul(t, e); 189 | 190 | MAM_ASSERT(poly_coeff_mul(e, a) == MAM_POLY_COEFF_ONE); 191 | 192 | return e; 193 | } 194 | -------------------------------------------------------------------------------- /mam/ntru/tests/BUILD: -------------------------------------------------------------------------------- 1 | cc_test( 2 | name = "test_ntru", 3 | timeout = "short", 4 | srcs = ["test_ntru.c"], 5 | deps = [ 6 | "//mam/ntru", 7 | "@unity", 8 | ], 9 | ) 10 | 11 | cc_test( 12 | name = "test_poly_mred_binary", 13 | timeout = "moderate", 14 | srcs = ["test_poly.c"], 15 | deps = [ 16 | "//mam/ntru:poly_mred_binary", 17 | "@unity", 18 | ], 19 | ) 20 | 21 | cc_test( 22 | name = "test_poly_no_mred_binary", 23 | timeout = "moderate", 24 | srcs = ["test_poly.c"], 25 | deps = [ 26 | "//mam/ntru:poly_no_mred_binary", 27 | "@unity", 28 | ], 29 | ) 30 | -------------------------------------------------------------------------------- /mam/ntru/tests/test_ntru.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https://github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by 6 | * [ITSec Lab] 7 | * 8 | * Refer to the LICENSE file for licensing information 9 | */ 10 | 11 | #include 12 | 13 | #include "common/trinary/trit_tryte.h" 14 | #include "mam/ntru/ntru.h" 15 | #include "mam/ntru/poly.h" 16 | #include "mam/pb3/pb3.h" 17 | 18 | static void ntru_test(void) { 19 | mam_spongos_t spongos; 20 | mam_prng_t prng; 21 | mam_ntru_sk_t ntru; 22 | 23 | size_t i; 24 | size_t test_count = 30; 25 | MAM_POLY_DEF(f); 26 | MAM_POLY_DEF(f0); 27 | MAM_TRITS_DEF(nonce, 3 * 10); 28 | MAM_TRITS_DEF(key, MAM_PRNG_SECRET_KEY_SIZE); 29 | MAM_TRITS_DEF(ekey, MAM_NTRU_EKEY_SIZE); 30 | MAM_TRITS_DEF(dekey, MAM_NTRU_KEY_SIZE); 31 | nonce = MAM_TRITS_INIT(nonce, 3 * 10); 32 | key = MAM_TRITS_INIT(key, MAM_PRNG_SECRET_KEY_SIZE); 33 | ekey = MAM_TRITS_INIT(ekey, MAM_NTRU_EKEY_SIZE); 34 | dekey = MAM_TRITS_INIT(dekey, MAM_NTRU_KEY_SIZE); 35 | 36 | trits_from_str(key, 37 | "AAABBBCCCAAABBBCCCAAABBBCCC" 38 | "AAABBBCCCAAABBBCCCAAABBBCCC" 39 | "AAABBBCCCAAABBBCCCAAABBBCCC"); 40 | /* it'spongos safe to reuse sponge from spongos for prng */ 41 | /* as spongos is exclusively used in ntru_encr/ntru_decr. */ 42 | mam_spongos_init(&spongos); 43 | mam_prng_init(&prng, key); 44 | ntru_sk_reset(&ntru); 45 | trits_t pk = ntru_sk_pk_key(&ntru); 46 | 47 | i = 0; 48 | trits_set_zero(key); 49 | 50 | do { 51 | TEST_ASSERT_TRUE(trits_from_str(nonce, "NONCE9PK99")); 52 | trits_set_zero(pk); 53 | trits_put1(pk, 1); 54 | poly_small_from_trits(f, trits_take(pk, MAM_NTRU_SK_SIZE)); 55 | ntru_sk_gen(&ntru, &prng, nonce); 56 | memcpy(f0, ntru.f, sizeof(poly_t)); 57 | poly_add(f, f0, f); 58 | 59 | do { 60 | TEST_ASSERT_TRUE(trits_from_str(nonce, "NONCE9ENC9")); 61 | TEST_ASSERT(ntru_pk_encr(&ntru.public_key, &prng, &spongos, nonce, key, ekey) == RC_OK); 62 | 63 | TEST_ASSERT_TRUE(ntru_sk_decr(&ntru, &spongos, ekey, dekey)); 64 | TEST_ASSERT_TRUE(trits_cmp_eq(key, dekey)); 65 | 66 | trits_put1(ekey, trit_add(trits_get1(ekey), 1)); 67 | TEST_ASSERT_TRUE(!ntru_sk_decr(&ntru, &spongos, ekey, dekey)); 68 | TEST_ASSERT_TRUE(!trits_cmp_eq(key, dekey)); 69 | trits_put1(ekey, trit_sub(trits_get1(ekey), 1)); 70 | 71 | memcpy(ntru.f, f, sizeof(poly_t)); 72 | TEST_ASSERT_TRUE(!ntru_sk_decr(&ntru, &spongos, ekey, dekey)); 73 | TEST_ASSERT_TRUE(!trits_cmp_eq(key, dekey)); 74 | memcpy(ntru.f, f0, sizeof(poly_t)); 75 | 76 | trits_from_str(nonce, "NONCE9KEY9"); 77 | mam_prng_gen(&prng, MAM_PRNG_DST_SEC_KEY, nonce, key); 78 | } while (0 != (++i % (test_count / 10))); 79 | } while (++i < test_count); 80 | ntru_sk_reset(&ntru); 81 | } 82 | 83 | static void test_ntru_pk_serialization(void) { 84 | mam_ntru_pk_t_set_t ntru_set_1 = NULL; 85 | mam_ntru_pk_t_set_t ntru_set_2 = NULL; 86 | mam_ntru_pk_t ntru; 87 | tryte_t ntru_pk[MAM_NTRU_PK_SIZE / 3]; 88 | 89 | for (size_t i = 0; i < 26; i++) { 90 | memset(ntru_pk, 'A' + i, MAM_NTRU_PK_SIZE / 3); 91 | trytes_to_trits(ntru_pk, ntru.key, MAM_NTRU_PK_SIZE / 3); 92 | TEST_ASSERT(mam_ntru_pk_t_set_add(&ntru_set_1, &ntru) == RC_OK); 93 | } 94 | 95 | size_t size = mam_ntru_pks_serialized_size(ntru_set_1); 96 | 97 | TEST_ASSERT_EQUAL_INT(size, 26 * MAM_NTRU_PK_SIZE + pb3_sizeof_size_t(26)); 98 | 99 | trits_t trits = trits_alloc(size + pb3_sizeof_size_t(26)); 100 | 101 | TEST_ASSERT(mam_ntru_pks_serialize(ntru_set_1, &trits) == RC_OK); 102 | 103 | trits = trits_pickup_all(trits); 104 | 105 | TEST_ASSERT(mam_ntru_pks_deserialize(&trits, &ntru_set_2) == RC_OK); 106 | 107 | TEST_ASSERT_TRUE(mam_ntru_pk_t_set_cmp(ntru_set_1, ntru_set_2)); 108 | 109 | trits_free(trits); 110 | mam_ntru_pk_t_set_free(&ntru_set_1); 111 | mam_ntru_pk_t_set_free(&ntru_set_2); 112 | } 113 | 114 | static void test_ntru_sk_serialization(void) { 115 | mam_ntru_sk_t_set_t ntru_sk_set_1 = NULL; 116 | mam_ntru_sk_t_set_t ntru_sk_set_2 = NULL; 117 | mam_ntru_sk_t ntru_sk; 118 | mam_prng_t prng; 119 | MAM_TRITS_DEF(key, MAM_PRNG_SECRET_KEY_SIZE); 120 | MAM_TRITS_DEF(nonce, 3 * 10); 121 | key = MAM_TRITS_INIT(key, MAM_PRNG_SECRET_KEY_SIZE); 122 | nonce = MAM_TRITS_INIT(nonce, 3 * 10); 123 | 124 | trits_from_str(key, 125 | "AAABBBCCCAAABBBCCCAAABBBCCC" 126 | "AAABBBCCCAAABBBCCCAAABBBCCC" 127 | "AAABBBCCCAAABBBCCCAAABBBCCC"); 128 | 129 | mam_prng_init(&prng, key); 130 | ntru_sk_reset(&ntru_sk); 131 | 132 | for (int i = -1; i <= 1; i++) { 133 | memset(nonce.p, i, 3 * 10); 134 | ntru_sk_gen(&ntru_sk, &prng, nonce); 135 | TEST_ASSERT(mam_ntru_sk_t_set_add(&ntru_sk_set_1, &ntru_sk) == RC_OK); 136 | } 137 | 138 | size_t size = mam_ntru_sks_serialized_size(ntru_sk_set_1); 139 | 140 | TEST_ASSERT_EQUAL_INT(size, 3 * (MAM_NTRU_PK_SIZE + MAM_NTRU_SK_SIZE) + pb3_sizeof_size_t(3)); 141 | 142 | trits_t trits = trits_alloc(size); 143 | 144 | TEST_ASSERT(mam_ntru_sks_serialize(ntru_sk_set_1, &trits) == RC_OK); 145 | trits = trits_pickup_all(trits); 146 | TEST_ASSERT(mam_ntru_sks_deserialize(&trits, &ntru_sk_set_2) == RC_OK); 147 | 148 | TEST_ASSERT_TRUE(mam_ntru_sk_t_set_cmp(ntru_sk_set_1, ntru_sk_set_2)); 149 | 150 | mam_ntru_sk_t_set_free(&ntru_sk_set_1); 151 | mam_ntru_sk_t_set_free(&ntru_sk_set_2); 152 | 153 | trits_free(trits); 154 | } 155 | 156 | int main(void) { 157 | UNITY_BEGIN(); 158 | 159 | RUN_TEST(ntru_test); 160 | RUN_TEST(test_ntru_pk_serialization); 161 | RUN_TEST(test_ntru_sk_serialization); 162 | 163 | return UNITY_END(); 164 | } 165 | -------------------------------------------------------------------------------- /mam/pb3/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//visibility:public"]) 2 | 3 | cc_library( 4 | name = "pb3", 5 | srcs = ["pb3.c"], 6 | hdrs = ["pb3.h"], 7 | deps = [ 8 | "//mam/sponge:spongos", 9 | "@org_iota_common//common:errors", 10 | "@org_iota_common//common/trinary:trit_long", 11 | ], 12 | ) 13 | -------------------------------------------------------------------------------- /mam/pb3/tests/BUILD: -------------------------------------------------------------------------------- 1 | cc_test( 2 | name = "test_pb3", 3 | timeout = "short", 4 | srcs = ["test_pb3.c"], 5 | deps = [ 6 | "//mam/pb3", 7 | "@unity", 8 | ], 9 | ) 10 | -------------------------------------------------------------------------------- /mam/pb3/tests/test_pb3.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https://github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by 6 | * [ITSec Lab] 7 | * 8 | * Refer to the LICENSE file for licensing information 9 | */ 10 | 11 | #include 12 | 13 | #include "mam/pb3/pb3.h" 14 | 15 | static bool pb3_size_t_test(size_t n) { 16 | retcode_t e; 17 | bool ok = true; 18 | size_t k = pb3_sizeof_size_t(n); 19 | size_t m = 0; 20 | MAM_TRITS_DEF(b0, 3 * 14); /* 14 trytes max */ 21 | trits_t b; 22 | b0 = MAM_TRITS_INIT(b0, 3 * 14); /* 14 trytes max */ 23 | 24 | b = trits_take(b0, k); 25 | pb3_encode_size_t(n, &b); 26 | ok = ok && trits_is_empty(b); 27 | 28 | b = trits_take(b0, k); 29 | e = pb3_decode_size_t(&m, &b); 30 | ok = ok && trits_is_empty(b); 31 | 32 | return (e == RC_OK && ok && m == n); 33 | } 34 | 35 | static bool pb3_test_size_t_overflow() { 36 | retcode_t e; 37 | size_t n; 38 | MAM_TRITS_DEF(x, 3 * (1 + 8)); 39 | 40 | x = MAM_TRITS_INIT(x, 3 * (1 + 8)); 41 | trits_set1(x, 1); 42 | trits_put3(x, 8); 43 | /* x = pb3_encode_size_t((27^8-1)/2) > 2^32 */ 44 | 45 | e = pb3_decode_size_t(&n, &x); 46 | return e == RC_MAM_TRITS_SIZE_T_NOT_SUPPORTED; 47 | } 48 | 49 | static void pb3_size_t_tests(void) { 50 | size_t n, k; 51 | 52 | n = 0; 53 | for (k = 0; k < 1000; ++k) { 54 | TEST_ASSERT_TRUE(pb3_size_t_test(n++)); 55 | }; 56 | 57 | if ((5 * sizeof(size_t) + 2) / 3 < 14) { 58 | /* this should be the case on a 32-bit platform */ 59 | for (n = 1, k = 0; k < sizeof(size_t); ++k) { 60 | n *= 243; 61 | } 62 | n -= 50; 63 | for (k = 0; k < 100; ++k) { 64 | TEST_ASSERT_TRUE(pb3_size_t_test(n++)); 65 | } 66 | 67 | n = (size_t)0 - 100; 68 | for (k = 0; k < 100; ++k) { 69 | TEST_ASSERT_TRUE(pb3_size_t_test(n++)); 70 | } 71 | TEST_ASSERT_TRUE(pb3_test_size_t_overflow()); 72 | } else { 73 | /* this should be the case on a 64-bit platform */ 74 | /*n = SIZE_MAX;*/ 75 | n = (size_t)MAM_TRITS_SIZE_MAX; 76 | n -= 99; 77 | for (k = 0; k < 100; ++k) { 78 | TEST_ASSERT_TRUE(pb3_size_t_test(n++)); 79 | } 80 | TEST_ASSERT_TRUE(!pb3_test_size_t_overflow()); 81 | } 82 | } 83 | 84 | int main(void) { 85 | UNITY_BEGIN(); 86 | 87 | RUN_TEST(pb3_size_t_tests); 88 | 89 | return UNITY_END(); 90 | } 91 | -------------------------------------------------------------------------------- /mam/prng/BUILD: -------------------------------------------------------------------------------- 1 | cc_library( 2 | name = "prng", 3 | srcs = ["prng.c"], 4 | hdrs = ["prng.h"], 5 | visibility = ["//visibility:public"], 6 | deps = [ 7 | "//mam:defs", 8 | "//mam/pb3", 9 | "//mam/sponge", 10 | "//mam/trits", 11 | "@org_iota_common//common:errors", 12 | "@org_iota_common//utils:memset_safe", 13 | ], 14 | ) 15 | -------------------------------------------------------------------------------- /mam/prng/prng.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https://github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by [ITSec Lab] 6 | * 7 | * Refer to the LICENSE file for licensing information 8 | */ 9 | 10 | #include "mam/prng/prng.h" 11 | #include "mam/sponge/sponge.h" 12 | 13 | retcode_t mam_prng_init(mam_prng_t *const prng, trits_t const secret_key) { 14 | if (prng == NULL) { 15 | return RC_NULL_PARAM; 16 | } 17 | 18 | if (trits_size(secret_key) != MAM_PRNG_SECRET_KEY_SIZE) { 19 | return RC_INVALID_PARAM; 20 | } 21 | 22 | memcpy(prng->secret_key, trits_begin(secret_key), MAM_PRNG_SECRET_KEY_SIZE); 23 | 24 | return RC_OK; 25 | } 26 | 27 | retcode_t mam_prng_gen5(mam_prng_t const *const prng, mam_prng_destination_tryte_t const destination, 28 | trits_t const nonce1, trits_t const nonce2, trits_t const nonce3, trits_t const nonce4, 29 | trits_t const nonce5, trits_t output) { 30 | mam_sponge_t sponge; 31 | trits_t inputs[7]; 32 | trit_t dest[3]; 33 | 34 | if (prng == NULL) { 35 | return RC_NULL_PARAM; 36 | } 37 | 38 | inputs[0] = trits_from_rep(MAM_PRNG_SECRET_KEY_SIZE, prng->secret_key); 39 | inputs[1] = trits_from_rep(3, dest); 40 | inputs[2] = nonce1; 41 | inputs[3] = nonce2; 42 | inputs[4] = nonce3; 43 | inputs[5] = nonce4; 44 | inputs[6] = nonce5; 45 | trits_put3(inputs[1], destination); 46 | 47 | mam_sponge_init(&sponge); 48 | mam_sponge_absorbn(&sponge, MAM_SPONGE_CTL_KEY, 7, inputs); 49 | mam_sponge_squeeze(&sponge, MAM_SPONGE_CTL_PRN, output); 50 | 51 | return RC_OK; 52 | } 53 | -------------------------------------------------------------------------------- /mam/prng/prng.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https://github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by [ITSec Lab] 6 | * 7 | * Refer to the LICENSE file for licensing information 8 | */ 9 | 10 | /** 11 | * @ingroup mam 12 | * 13 | * @{ 14 | * 15 | * @file 16 | * @brief The PRNG layer supports the generation of cryptographically strong pseudorandom trit arrays 17 | * 18 | */ 19 | #ifndef __MAM_PRNG_PRNG_H__ 20 | #define __MAM_PRNG_PRNG_H__ 21 | 22 | #include "common/errors.h" 23 | #include "mam/defs.h" 24 | #include "mam/pb3/pb3.h" 25 | #include "mam/trits/trits.h" 26 | #include "utils/memset_safe.h" 27 | 28 | /** @brief Size of a PRNG secret key */ 29 | #define MAM_PRNG_SECRET_KEY_SIZE 243 30 | 31 | #ifdef __cplusplus 32 | extern "C" { 33 | #endif 34 | 35 | /** @brief Destination context encoded in one tryte */ 36 | typedef enum mam_prng_destination_tryte_e { 37 | /** @brief PRNG AE destination tryte */ 38 | MAM_PRNG_DST_SEC_KEY = 0, 39 | /** @brief PRNG WOTS destination tryte */ 40 | MAM_PRNG_DST_WOTS_KEY = 1, 41 | /** @brief PRNG NTRU destination tryte */ 42 | MAM_PRNG_DST_NTRU_KEY = 2 43 | } mam_prng_destination_tryte_t; 44 | 45 | typedef struct mam_prng_s { 46 | trit_t secret_key[MAM_PRNG_SECRET_KEY_SIZE]; 47 | } mam_prng_t; 48 | 49 | /** 50 | * @brief Initializes a PRNG with a secret key 51 | * 52 | * @param[out] prng The PRNG 53 | * @param[in] secret_key The secret key 54 | * 55 | * @return a status code 56 | */ 57 | retcode_t mam_prng_init(mam_prng_t *const prng, trits_t const secret_key); 58 | 59 | /** 60 | * @brief Safely resets a PRNG secret key 61 | * 62 | * @param[out] prng The PRNG 63 | * 64 | * @return a status code 65 | */ 66 | static inline retcode_t mam_prng_reset(mam_prng_t *const prng) { 67 | if (prng == NULL) { 68 | return RC_NULL_PARAM; 69 | } 70 | 71 | memset_safe(prng->secret_key, MAM_PRNG_SECRET_KEY_SIZE, 0, MAM_PRNG_SECRET_KEY_SIZE); 72 | 73 | return RC_OK; 74 | } 75 | 76 | /** 77 | * @brief Generates pseudo random trits with five nonces 78 | * 79 | * @param[in] prng A PRNG 80 | * @param[in] destination A destination tryte 81 | * @param[in] nonce1 The first nonce 82 | * @param[in] nonce2 The second nonce 83 | * @param[in] nonce3 The third nonce 84 | * @param[in] nonce4 The fourth nonce 85 | * @param[in] nonce5 The fifth nonce 86 | * @param[out] output The pseudo random trits 87 | * 88 | * @return a status code 89 | */ 90 | retcode_t mam_prng_gen5(mam_prng_t const *const prng, mam_prng_destination_tryte_t const destination, 91 | trits_t const nonce1, trits_t const nonce2, trits_t const nonce3, trits_t const nonce4, 92 | trits_t const nonce5, trits_t output); 93 | 94 | /** 95 | * @brief Generates pseudo random trits with three nonces 96 | * 97 | * @param[in] prng A PRNG 98 | * @param[in] destination A destination tryte 99 | * @param[in] nonce1 The first nonce 100 | * @param[in] nonce2 The second nonce 101 | * @param[in] nonce3 The third nonce 102 | * @param[out] output The pseudo random trits 103 | * 104 | * @return a status code 105 | */ 106 | static inline retcode_t mam_prng_gen3(mam_prng_t const *const prng, mam_prng_destination_tryte_t const destination, 107 | trits_t const nonce1, trits_t const nonce2, trits_t const nonce3, 108 | trits_t output) { 109 | return mam_prng_gen5(prng, destination, nonce1, nonce2, nonce3, trits_null(), trits_null(), output); 110 | } 111 | 112 | /** 113 | * @brief Generates pseudo random trits with two nonces 114 | * 115 | * @param[in] prng A PRNG 116 | * @param[in] destination A destination tryte 117 | * @param[in] nonce1 The first nonce 118 | * @param[in] nonce2 The second nonce 119 | * @param[out] output The pseudo random trits 120 | * 121 | * @return a status code 122 | */ 123 | static inline retcode_t mam_prng_gen2(mam_prng_t const *const prng, mam_prng_destination_tryte_t const destination, 124 | trits_t const nonce1, trits_t const nonce2, trits_t output) { 125 | return mam_prng_gen5(prng, destination, nonce1, nonce2, trits_null(), trits_null(), trits_null(), output); 126 | } 127 | 128 | /** 129 | * @brief Generates pseudo random trits with a nonce 130 | * 131 | * @param[in] prng A PRNG 132 | * @param[in] destination A destination tryte 133 | * @param[in] nonce The nonce 134 | * @param[out] output The pseudo random trits 135 | * 136 | * @return a status code 137 | */ 138 | static inline retcode_t mam_prng_gen(mam_prng_t const *const prng, mam_prng_destination_tryte_t const destination, 139 | trits_t const nonce, trits_t output) { 140 | return mam_prng_gen5(prng, destination, nonce, trits_null(), trits_null(), trits_null(), trits_null(), output); 141 | } 142 | 143 | /** 144 | * @brief Size of a serialized PRNG 145 | * 146 | * @returns the size 147 | */ 148 | static inline size_t mam_prng_serialized_size() { return MAM_PRNG_SECRET_KEY_SIZE; } 149 | 150 | /** 151 | * @brief Serializes a PRNG into a trits buffer 152 | * 153 | * @param[in] prng The PRNG 154 | * @param[out] buffer The trits buffer 155 | */ 156 | static inline void mam_prng_serialize(mam_prng_t const *const prng, trits_t *const buffer) { 157 | pb3_encode_ntrytes(trits_from_rep(MAM_PRNG_SECRET_KEY_SIZE, prng->secret_key), buffer); 158 | } 159 | 160 | /** 161 | * @brief Deserializes a PRNG from a trits buffer 162 | * 163 | * @param[in] buffer The trits buffer 164 | * @param[out] prng The PRNG 165 | * 166 | * @return a status code 167 | */ 168 | static inline retcode_t mam_prng_deserialize(trits_t *const buffer, mam_prng_t *const prng) { 169 | return pb3_decode_ntrytes(trits_from_rep(MAM_PRNG_SECRET_KEY_SIZE, prng->secret_key), buffer); 170 | } 171 | 172 | #ifdef __cplusplus 173 | } 174 | #endif 175 | 176 | #endif // __MAM_PRNG_PRNG_H__ 177 | 178 | /** @} */ 179 | -------------------------------------------------------------------------------- /mam/prng/tests/BUILD: -------------------------------------------------------------------------------- 1 | cc_test( 2 | name = "test_prng", 3 | timeout = "short", 4 | srcs = ["test_prng.c"], 5 | visibility = ["//visibility:private"], 6 | deps = [ 7 | "//mam/prng", 8 | "@org_iota_common//common/trinary:trit_tryte", 9 | "@unity", 10 | ], 11 | ) 12 | -------------------------------------------------------------------------------- /mam/prng/tests/test_prng.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https://github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by [ITSec Lab] 6 | * 7 | * Refer to the LICENSE file for licensing information 8 | */ 9 | 10 | #include 11 | 12 | #include "common/trinary/trit_tryte.h" 13 | #include "mam/prng/prng.h" 14 | 15 | static void test_prng(void) { 16 | mam_prng_t prng; 17 | 18 | MAM_TRITS_DEF(K, MAM_PRNG_SECRET_KEY_SIZE); 19 | MAM_TRITS_DEF(N, 18); 20 | MAM_TRITS_DEF(Y1, 243 * 2 + 18); 21 | MAM_TRITS_DEF(Y2, 243 * 2 + 18); 22 | K = MAM_TRITS_INIT(K, MAM_PRNG_SECRET_KEY_SIZE); 23 | N = MAM_TRITS_INIT(N, 18); 24 | Y1 = MAM_TRITS_INIT(Y1, 243 * 2 + 18); 25 | Y2 = MAM_TRITS_INIT(Y2, 243 * 2 + 18); 26 | 27 | trits_set_zero(K); 28 | trits_set_zero(N); 29 | trits_from_str(K, 30 | "NOPQRSTUVWXYZ9ABCDEFGHIJKLM" 31 | "NOPQRSTUVWXYZ9ABCDEFGHIJKLM" 32 | "NOPQRSTUVWXYZ9ABCDEFGHIJKLM"); 33 | 34 | mam_prng_init(&prng, K); 35 | mam_prng_gen(&prng, 0, N, Y1); 36 | mam_prng_gen(&prng, 1, N, Y2); 37 | 38 | TEST_ASSERT_TRUE(!trits_cmp_eq(Y1, Y2)); 39 | } 40 | 41 | static void test_prng_serialization(void) { 42 | mam_prng_t prng1; 43 | mam_prng_t prng2; 44 | tryte_t secret_key_str[MAM_PRNG_SECRET_KEY_SIZE / 3]; 45 | 46 | memset(secret_key_str, 'M', MAM_PRNG_SECRET_KEY_SIZE / 3); 47 | trytes_to_trits(secret_key_str, prng1.secret_key, MAM_PRNG_SECRET_KEY_SIZE / 3); 48 | 49 | size_t size = mam_prng_serialized_size(); 50 | 51 | TEST_ASSERT_EQUAL_INT(size, MAM_PRNG_SECRET_KEY_SIZE); 52 | 53 | trits_t trits = trits_alloc(size); 54 | 55 | mam_prng_serialize(&prng1, &trits); 56 | trits = trits_pickup_all(trits); 57 | 58 | TEST_ASSERT(mam_prng_deserialize(&trits, &prng2) == RC_OK); 59 | 60 | TEST_ASSERT_EQUAL_MEMORY(prng1.secret_key, prng2.secret_key, MAM_PRNG_SECRET_KEY_SIZE); 61 | 62 | trits_free(trits); 63 | } 64 | 65 | int main(void) { 66 | UNITY_BEGIN(); 67 | 68 | RUN_TEST(test_prng); 69 | RUN_TEST(test_prng_serialization); 70 | 71 | return UNITY_END(); 72 | } 73 | -------------------------------------------------------------------------------- /mam/prototype/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//visibility:public"]) 2 | 3 | cc_library( 4 | name = "mam", 5 | srcs = ["mam.c"], 6 | hdrs = ["mam.h"], 7 | deps = 8 | [ 9 | ":mask", 10 | "@org_iota_common//common/crypto/curl-p:hamming", 11 | "@org_iota_common//common/trinary:trit_long", 12 | "@org_iota_common//utils:merkle", 13 | ], 14 | ) 15 | 16 | cc_library( 17 | name = "mask", 18 | srcs = ["mask.c"], 19 | hdrs = ["mask.h"], 20 | deps = 21 | [ 22 | "@org_iota_common//common/crypto/curl-p:trit", 23 | "@org_iota_common//common/trinary:add", 24 | ], 25 | ) 26 | -------------------------------------------------------------------------------- /mam/prototype/mam.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https://github.com/iotaledger/entangled 4 | * 5 | * Refer to the LICENSE file for licensing information 6 | */ 7 | 8 | #ifndef __MAM_PROTOTYPE_MAM_H__ 9 | #define __MAM_PROTOTYPE_MAM_H__ 10 | 11 | #include "common/crypto/curl-p/hamming.h" 12 | #include "common/trinary/trit_long.h" 13 | #include "mam/prototype/mask.h" 14 | 15 | #ifdef __cplusplus 16 | extern "C" { 17 | #endif 18 | 19 | /** 20 | * Initializes the encryption/decryption state for a MAM session 21 | * 22 | * @param side_key The encryption key 23 | * @param side_key_length The size of the encryption key 24 | * @param merkle_root The merkle root 25 | * @param enc_curl A curl instance used for encryption/decryption 26 | */ 27 | void mam_init_encryption(trit_t const *const side_key, size_t const side_key_length, trit_t const *const merkle_root, 28 | Curl *const enc_curl); 29 | 30 | /** 31 | * Computes the minimum length of a payload 32 | * 33 | * @param message_length The length of the message 34 | * @param merkle_tree_length The length of the merkle tree 35 | * @param index The leaf index 36 | * @param security The security used to generate addresses 37 | * 38 | * @return The minimum length of the payload 39 | */ 40 | int payload_min_length(size_t const message_length, size_t const merkle_tree_length, size_t const index, 41 | size_t const security); 42 | 43 | /** 44 | * Creates a signed, encrypted payload from a message 45 | * 46 | * @param payload The payload to be filled - Must be allocated 47 | * @param payload_length The payload length 48 | * @param message The message 49 | * @param message_length The message length 50 | * @param side_key The encryption key 51 | * @param side_key_length The length of the encryption key 52 | * @param merkle_tree The merkle tree 53 | * @param merkle_tree_length The length of the merkle tree 54 | * @param leaf_count The number of leaves of the merkle tree 55 | * @param index The leaf index 56 | * @param next_root The merkle root of the next MAM payload 57 | * @param start The offset used to generate addresses 58 | * @param seed The seed used to generate addresses - Not sent over the network 59 | * @param security - The security used to generate addresses 60 | * @param enc_curl A curl instance used for encryption/decryption 61 | * 62 | * @return Success/error code 63 | */ 64 | int mam_create(trit_t *const payload, size_t const payload_length, trit_t const *const message, 65 | size_t const message_length, trit_t const *const side_key, size_t const side_key_length, 66 | trit_t const *const merkle_tree, size_t const merkle_tree_length, size_t const leaf_count, 67 | size_t const index, trit_t const *const next_root, size_t const start, trit_t const *const seed, 68 | size_t const security, Curl *const enc_curl); 69 | 70 | /** 71 | * Decrypts, parses and validates an encrypted payload 72 | * 73 | * @param payload The payload 74 | * @param payload_length The length of the payload 75 | * @param message The message to be filled - Must be allocated 76 | * @param message_length The length of the message 77 | * @param side_key The decryption key 78 | * @param side_key_length The length of the decryption key 79 | * @param root The merkle root 80 | * @param index The leaf index 81 | * @param next_root The merkle root of the next MAM payload 82 | * @param security The security used to generate addresses 83 | * @param enc_curl A curl instance used for encryption/decryption 84 | * 85 | * @return Success/error code 86 | */ 87 | int mam_parse(trit_t *const payload, size_t const payload_length, trit_t *const message, size_t *const message_length, 88 | trit_t const *const side_key, size_t const side_key_length, trit_t const *const root, size_t *const index, 89 | trit_t *const next_root, size_t *const security, Curl *const enc_curl); 90 | 91 | #ifdef __cplusplus 92 | } 93 | #endif 94 | 95 | #endif //__MAM_PROTOTYPE_MAM_H__ 96 | -------------------------------------------------------------------------------- /mam/prototype/mask.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https://github.com/iotaledger/entangled 4 | * 5 | * Refer to the LICENSE file for licensing information 6 | */ 7 | 8 | #include 9 | 10 | #include "common/trinary/add.h" 11 | #include "mam/prototype/mask.h" 12 | 13 | void mask(trit_t *const dest, trit_t const *const message, size_t const length, Curl *const c) { 14 | size_t chunk_length; 15 | trit_t chunk[HASH_LENGTH_TRIT]; 16 | for (size_t i = 0; i < length; i += HASH_LENGTH_TRIT) { 17 | chunk_length = length - i < HASH_LENGTH_TRIT ? length - i : HASH_LENGTH_TRIT; 18 | memcpy(chunk, &message[i], chunk_length * sizeof(trit_t)); 19 | for (size_t j = 0; j < chunk_length; j++) { 20 | dest[i + j] = trit_sum(chunk[j], c->state[j]); 21 | } 22 | curl_absorb(c, chunk, chunk_length); 23 | } 24 | } 25 | 26 | void unmask(trit_t *const dest, trit_t const *const cipher, size_t const length, Curl *const c) { 27 | size_t chunk_length; 28 | for (size_t i = 0; i < length; i += HASH_LENGTH_TRIT) { 29 | chunk_length = length - i < HASH_LENGTH_TRIT ? length - i : HASH_LENGTH_TRIT; 30 | for (size_t j = 0; j < chunk_length; j++) { 31 | dest[i + j] = trit_sum(cipher[i + j], -c->state[j]); 32 | } 33 | curl_absorb(c, &dest[i], chunk_length); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /mam/prototype/mask.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https://github.com/iotaledger/entangled 4 | * 5 | * Refer to the LICENSE file for licensing information 6 | */ 7 | 8 | #ifndef __MAM_PROTOTYPE_MASK_H__ 9 | #define __MAM_PROTOTYPE_MASK_H__ 10 | 11 | #include "common/crypto/curl-p/trit.h" 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif 16 | 17 | /** 18 | * Masks a given message with a curl instance state 19 | * 20 | * @param dest Destination of the masked message 21 | * @param message Message to be masked 22 | * @param length Length of the message 23 | * @param c The curl instance used to mask the message 24 | */ 25 | void mask(trit_t *const dest, trit_t const *const message, size_t const length, Curl *const c); 26 | 27 | /** 28 | * Unmasks a given cipher with a curl instance state 29 | * 30 | * @param dest Destination of the unmasked cipher 31 | * @param cipher Cipher to be unmasked 32 | * @param length Length of the cipher 33 | * @param c The curl instance used to unmask the cipher 34 | */ 35 | void unmask(trit_t *const dest, trit_t const *const cipher, size_t const length, Curl *const c); 36 | 37 | #ifdef __cplusplus 38 | } 39 | #endif 40 | 41 | #endif //__MAM_PROTOTYPE_MASK_H__ 42 | -------------------------------------------------------------------------------- /mam/prototype/tests/BUILD: -------------------------------------------------------------------------------- 1 | cc_test( 2 | name = "test_mam", 3 | timeout = "long", 4 | srcs = ["test_mam.c"], 5 | linkopts = ["-lpthread"], 6 | deps = 7 | [ 8 | "//mam/prototype:mam", 9 | "@org_iota_common//common/trinary:trit_tryte", 10 | "@unity", 11 | ], 12 | ) 13 | 14 | cc_test( 15 | name = "test_mask", 16 | timeout = "short", 17 | srcs = ["test_mask.c"], 18 | deps = 19 | [ 20 | "//mam/prototype:mask", 21 | "@org_iota_common//common/trinary:trit_tryte", 22 | "@unity", 23 | ], 24 | ) 25 | -------------------------------------------------------------------------------- /mam/prototype/tests/test_mam.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https://github.com/iotaledger/entangled 4 | * 5 | * Refer to the LICENSE file for licensing information 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include "common/crypto/iss/v2/iss_curl.h" 13 | #include "common/trinary/trit_tryte.h" 14 | #include "mam/prototype/mam.h" 15 | #include "utils/merkle.h" 16 | 17 | void test_mam_sec(int security) { 18 | char *const seed = 19 | "TX9XRR9SRCOBMTYDTMKNEIJCSZIMEUPWCNLC9DPDZKKAEMEFVSTEVUFTRUZXEHLULEIYJIEO" 20 | "WIC9STAHW"; 21 | char *const message = 22 | "D9999999JDLILILID9999999D9999999GC999999FB999999EA999999D9999999YELILILI" 23 | "GGOFQGHCMCOC9999WAFEA999UA999999JHTB9999VFLILILIFGOFQGHCCCOC9999ABFEA999" 24 | "UA999999WGSB9999SGLILILIEGOFQGHCTBOC99999BFEA999UA999999WGSB9999PHLILILI" 25 | "DGOFQGHCJBOC9999ZAFEA999VA999999WGSB9999N999X999D999H999L999P999T999F999" 26 | "H999D999"; 27 | char *const side_key = 28 | "QOLOACG9BNUYLERQTZPPW9VKIOPDRTPMFZCYWGNVKIZJEYBWJDXASOXNDMZGBNYFVBCFBQBX" 29 | "SCCAFFRIO"; 30 | 31 | trit_t seed_trits[3 * strlen(seed) * sizeof(trit_t)]; 32 | trit_t side_key_trits[3 * strlen(side_key) * sizeof(trit_t)]; 33 | trit_t message_trits[3 * strlen(message) * sizeof(trit_t)]; 34 | 35 | trytes_to_trits((tryte_t *)seed, seed_trits, strlen(seed)); 36 | trytes_to_trits((tryte_t *)side_key, side_key_trits, strlen(side_key)); 37 | trytes_to_trits((tryte_t *)message, message_trits, strlen(message)); 38 | 39 | size_t index = 7; 40 | size_t message_length = strlen(message) * 3; 41 | 42 | size_t start = 0; 43 | size_t count = 8; 44 | size_t next_start = start + count; 45 | size_t next_count = 1; 46 | size_t tree_size = merkle_size(count); 47 | size_t next_tree_size = merkle_size(next_count); 48 | trit_t merkle_tree[tree_size * HASH_LENGTH_TRIT]; 49 | trit_t next_root[next_tree_size * HASH_LENGTH_TRIT]; 50 | int payload_length = payload_min_length(message_length, tree_size * HASH_LENGTH_TRIT, index, security); 51 | trit_t *payload = (trit_t *)malloc(payload_length * sizeof(trit_t)); 52 | 53 | Curl curl; 54 | curl.type = CURL_P_27; 55 | curl_init(&curl); 56 | TEST_ASSERT_EQUAL_INT(0, merkle_create(merkle_tree, count, seed_trits, start, security, &curl)); 57 | curl_reset(&curl); 58 | TEST_ASSERT_EQUAL_INT(0, merkle_create(next_root, next_count, seed_trits, next_start, security, &curl)); 59 | curl_reset(&curl); 60 | payload_length = mam_create(payload, payload_length, message_trits, message_length, side_key_trits, 61 | strlen(side_key) * 3, merkle_tree, tree_size * HASH_LENGTH_TRIT, count, index, next_root, 62 | start, seed_trits, security, &curl); 63 | TEST_ASSERT_TRUE(payload_length != -1); 64 | curl_reset(&curl); 65 | 66 | size_t parsed_index = -1; 67 | size_t parsed_message_length = -1; 68 | trit_t parsed_next_root[HASH_LENGTH_TRIT]; 69 | size_t parsed_message_trits[message_length]; 70 | size_t parsed_security = -1; 71 | 72 | TEST_ASSERT_EQUAL_INT( 73 | 0, mam_parse(payload, payload_length, (trit_t *)parsed_message_trits, &parsed_message_length, side_key_trits, 74 | strlen(side_key) * 3, merkle_tree, &parsed_index, parsed_next_root, &parsed_security, &curl)); 75 | 76 | TEST_ASSERT_EQUAL_INT(index, parsed_index); 77 | TEST_ASSERT_EQUAL_MEMORY(next_root, parsed_next_root, HASH_LENGTH_TRIT); 78 | TEST_ASSERT_EQUAL_MEMORY(message_trits, parsed_message_trits, parsed_message_length); 79 | TEST_ASSERT_EQUAL_INT(security, parsed_security); 80 | free(payload); 81 | } 82 | 83 | void test_mam() { 84 | test_mam_sec(1); 85 | test_mam_sec(2); 86 | test_mam_sec(3); 87 | } 88 | 89 | int main(void) { 90 | UNITY_BEGIN(); 91 | 92 | RUN_TEST(test_mam); 93 | 94 | return UNITY_END(); 95 | } 96 | -------------------------------------------------------------------------------- /mam/prototype/tests/test_mask.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https://github.com/iotaledger/entangled 4 | * 5 | * Refer to the LICENSE file for licensing information 6 | */ 7 | 8 | #include 9 | 10 | #include 11 | 12 | #include "common/trinary/add.h" 13 | #include "common/trinary/trit_tryte.h" 14 | #include "mam/prototype/mask.h" 15 | 16 | void test_mask(void) { 17 | char* const payload = 18 | "AAMESSAGEFORYOU9AMESSAGEFORYOU9AMESSAGEFORYOU9AMESSAGEFORYOU9AMESS" 19 | "AGEFORYOU9AMESSAGEFORYOU9AMESSAGEFORYOU9AMESSAGEFORYOU9AMESSAGEFOR" 20 | "YOU9AMESSAGEFORYOU9AMESSAGEFORYOU9AMESSAGEFORYOU9AMESSAGEFORYOU9AM" 21 | "ESSAGEFORYOU9AMESSAGEFORYOU9AMESSAGEFORYOU9AMESSAGEFORYOU9AMESSAGE" 22 | "FORYOU9AMESSAGEFORYOU9AMESSAGEFORYOU9MESSAGEFORYOU9"; 23 | char* const auth_id = "MYMERKLEROOTHASH"; 24 | size_t const payload_size = strlen(payload); 25 | size_t const auth_id_size = strlen(auth_id); 26 | trit_t payload_trits[3 * payload_size]; 27 | trit_t cipher_trits[3 * payload_size]; 28 | trit_t auth_id_trits[3 * auth_id_size]; 29 | trytes_to_trits((tryte_t*)payload, payload_trits, payload_size); 30 | trytes_to_trits((tryte_t*)auth_id, auth_id_trits, auth_id_size); 31 | size_t index = 5; 32 | Curl c; 33 | c.type = CURL_P_27; 34 | 35 | add_assign(auth_id_trits, 3 * auth_id_size, index); 36 | 37 | curl_init(&c); 38 | curl_absorb(&c, auth_id_trits, 3 * auth_id_size); 39 | mask(cipher_trits, payload_trits, 3 * payload_size, &c); 40 | 41 | curl_reset(&c); 42 | curl_absorb(&c, auth_id_trits, 3 * auth_id_size); 43 | unmask(cipher_trits, cipher_trits, 3 * payload_size, &c); 44 | 45 | TEST_ASSERT_EQUAL_MEMORY(payload_trits, cipher_trits, 3 * payload_size); 46 | } 47 | 48 | int main(void) { 49 | UNITY_BEGIN(); 50 | 51 | RUN_TEST(test_mask); 52 | 53 | return UNITY_END(); 54 | } 55 | -------------------------------------------------------------------------------- /mam/psk/BUILD: -------------------------------------------------------------------------------- 1 | load("@org_iota_common//utils/containers:typed_container_generator.bzl", "typed_container_generate") 2 | 3 | cc_library( 4 | name = "psk_hdr", 5 | hdrs = ["psk.h"], 6 | visibility = ["//visibility:private"], 7 | deps = [ 8 | "//mam/prng", 9 | "//mam/trits", 10 | "@org_iota_common//common:errors", 11 | "@org_iota_common//utils:memset_safe", 12 | ], 13 | ) 14 | 15 | cc_library( 16 | name = "psk", 17 | srcs = ["psk.c"], 18 | visibility = ["//visibility:public"], 19 | deps = [ 20 | ":mam_psk_t_set", 21 | ":psk_hdr", 22 | "//mam/pb3", 23 | ], 24 | ) 25 | 26 | typed_container_generate( 27 | additional_deps = ":psk_hdr", 28 | additional_include_path = "mam/psk/psk.h", 29 | container_type = "set", 30 | parent_directory = "mam/psk", 31 | value_type = "mam_psk_t", 32 | ) 33 | -------------------------------------------------------------------------------- /mam/psk/psk.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https://github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by [ITSec Lab] 6 | * 7 | * Refer to the LICENSE file for licensing information 8 | */ 9 | 10 | #include "mam/psk/psk.h" 11 | #include "mam/pb3/pb3.h" 12 | #include "mam/psk/mam_psk_t_set.h" 13 | 14 | retcode_t mam_psk_gen(mam_psk_t *const psk, mam_prng_t const *const prng, tryte_t const *const id, 15 | tryte_t const *const nonce, size_t const nonce_length) { 16 | MAM_TRITS_DEF(nonce_trits, MAM_SPONGE_RATE); 17 | nonce_trits = MAM_TRITS_INIT(nonce_trits, MAM_SPONGE_RATE); 18 | 19 | if (psk == NULL || id == NULL || nonce == NULL) { 20 | return RC_NULL_PARAM; 21 | } 22 | 23 | trits_from_str(mam_psk_id(psk), (char const *)id); 24 | nonce_trits = trits_take_min(nonce_trits, nonce_length * 3); 25 | trits_from_str(nonce_trits, (char const *)nonce); 26 | 27 | return mam_prng_gen(prng, MAM_PRNG_DST_SEC_KEY, nonce_trits, mam_psk_key(psk)); 28 | } 29 | 30 | retcode_t mam_psks_destroy(mam_psk_t_set_t *const psks) { 31 | mam_psk_t_set_entry_t *entry = NULL; 32 | mam_psk_t_set_entry_t *tmp = NULL; 33 | 34 | if (psks == NULL) { 35 | return RC_NULL_PARAM; 36 | } 37 | 38 | SET_ITER(*psks, entry, tmp) { 39 | mam_psk_reset(&entry->value); 40 | mam_psk_t_set_remove_entry(psks, entry); 41 | } 42 | 43 | return RC_OK; 44 | } 45 | 46 | size_t mam_psks_serialized_size(mam_psk_t_set_t const psks) { 47 | return pb3_sizeof_size_t(mam_psk_t_set_size(psks)) + mam_psk_t_set_size(psks) * (MAM_PSK_ID_SIZE + MAM_PSK_KEY_SIZE); 48 | } 49 | 50 | retcode_t mam_psks_serialize(mam_psk_t_set_t const psks, trits_t *const trits) { 51 | mam_psk_t_set_entry_t *entry = NULL; 52 | mam_psk_t_set_entry_t *tmp = NULL; 53 | 54 | if (trits == NULL) { 55 | return RC_NULL_PARAM; 56 | } 57 | 58 | pb3_encode_size_t(mam_psk_t_set_size(psks), trits); 59 | 60 | SET_ITER(psks, entry, tmp) { 61 | pb3_encode_ntrytes(mam_psk_id(&entry->value), trits); 62 | pb3_encode_ntrytes(mam_psk_key(&entry->value), trits); 63 | } 64 | 65 | return RC_OK; 66 | } 67 | 68 | retcode_t mam_psks_deserialize(trits_t *const trits, mam_psk_t_set_t *const psks) { 69 | retcode_t ret = RC_OK; 70 | size_t psks_size = 0; 71 | mam_psk_t psk; 72 | 73 | if (trits == NULL || psks == NULL) { 74 | return RC_NULL_PARAM; 75 | } 76 | 77 | ERR_BIND_RETURN(pb3_decode_size_t(&psks_size, trits), ret); 78 | 79 | for (size_t i = 0; i < psks_size; i++) { 80 | ERR_BIND_RETURN(pb3_decode_ntrytes(mam_psk_id(&psk), trits), ret); 81 | ERR_BIND_RETURN(pb3_decode_ntrytes(mam_psk_key(&psk), trits), ret); 82 | ERR_BIND_RETURN(mam_psk_t_set_add(psks, &psk), ret); 83 | } 84 | 85 | return ret; 86 | } 87 | -------------------------------------------------------------------------------- /mam/psk/psk.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https://github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by [ITSec Lab] 6 | * 7 | * Refer to the LICENSE file for licensing information 8 | */ 9 | 10 | /** 11 | * @ingroup mam 12 | * 13 | * @{ 14 | * 15 | * @file 16 | * @brief A Pre-Shared Key (PSK) is a secret key of Authenticated Encryption (AE) 17 | * 18 | * It is preliminarily transmitted between the entities and is beyond the scope of MAM 19 | * The PSK id is an identifier of a group of recipients who share the same PSK 20 | * 21 | */ 22 | #ifndef __MAM_PSK_PSK_H__ 23 | #define __MAM_PSK_PSK_H__ 24 | 25 | #include "common/errors.h" 26 | #include "mam/prng/prng.h" 27 | #include "mam/trits/trits.h" 28 | #include "utils/memset_safe.h" 29 | 30 | /** @brief Size of a Pre-Shared Key ID */ 31 | #define MAM_PSK_ID_SIZE 81 32 | /** @brief Size of a Pre-Shared Key */ 33 | #define MAM_PSK_KEY_SIZE 243 34 | 35 | #ifdef __cplusplus 36 | extern "C" { 37 | #endif 38 | 39 | typedef struct mam_psk_s { 40 | trit_t id[MAM_PSK_ID_SIZE]; 41 | trit_t key[MAM_PSK_KEY_SIZE]; 42 | } mam_psk_t; 43 | 44 | typedef struct mam_psk_t_set_entry_s mam_psk_t_set_entry_t; 45 | typedef mam_psk_t_set_entry_t* mam_psk_t_set_t; 46 | 47 | /** 48 | * @brief Generates a pre-shared key with an id and a nonce 49 | * 50 | * @param[out] psk The pre-shared key 51 | * @param[in] prng A PRNG 52 | * @param[in] id The pre-shared key id 53 | * @param[in] nonce A trytes nonce 54 | * @param[in] nonce_length Length of the trytes nonce 55 | * 56 | * @return a status code 57 | */ 58 | retcode_t mam_psk_gen(mam_psk_t* const psk, mam_prng_t const* const prng, tryte_t const* const id, 59 | tryte_t const* const nonce, size_t const nonce_length); 60 | 61 | /** 62 | * @brief Safely resets a pre-shared key by clearing its secret part 63 | * 64 | * @param[out] psk The pre-shared key 65 | * 66 | * @return a status code 67 | */ 68 | static inline retcode_t mam_psk_reset(mam_psk_t* const psk) { 69 | if (psk == NULL) { 70 | return RC_NULL_PARAM; 71 | } 72 | 73 | memset_safe(psk->key, MAM_PSK_KEY_SIZE, 0, MAM_PSK_KEY_SIZE); 74 | 75 | return RC_OK; 76 | } 77 | 78 | /** 79 | * @brief Gets a pre-shared key id trits 80 | * 81 | * @param[in] psk The pre-shared key 82 | * 83 | * @return the pre-shared key id trits 84 | */ 85 | static inline trits_t mam_psk_id(mam_psk_t const* const psk) { 86 | if (psk == NULL) { 87 | return trits_null(); 88 | } 89 | 90 | return trits_from_rep(MAM_PSK_ID_SIZE, psk->id); 91 | } 92 | 93 | /** 94 | * @brief Gets a pre-shared key trits 95 | * 96 | * @param[in] psk The pre-shared key 97 | * 98 | * @return the pre-shared key trits 99 | */ 100 | static inline trits_t mam_psk_key(mam_psk_t const* const psk) { 101 | if (psk == NULL) { 102 | return trits_null(); 103 | } 104 | 105 | return trits_from_rep(MAM_PSK_KEY_SIZE, psk->key); 106 | } 107 | 108 | /** 109 | * @brief Safely destroys a set of pre-shared keys by clearing their secret part and releasing memory 110 | * 111 | * @param[out] psks The set of pre-shared keys 112 | * 113 | * @return a status code 114 | */ 115 | retcode_t mam_psks_destroy(mam_psk_t_set_t* const psks); 116 | 117 | /** 118 | * @brief Gets the size of a serialized set of pre-shared keys 119 | * 120 | * @param[in] psks The set of pre-shared keys 121 | * 122 | * @return the serialized size 123 | */ 124 | size_t mam_psks_serialized_size(mam_psk_t_set_t const psks); 125 | 126 | /** 127 | * @brief Serializes a set of pre-shared keys into a trits buffer 128 | * 129 | * @param[in] psks The set of pre-shared keys 130 | * @param[out] trits The trits buffer to serialize into 131 | * 132 | * @return a status code 133 | */ 134 | retcode_t mam_psks_serialize(mam_psk_t_set_t const psks, trits_t* const trits); 135 | 136 | /** 137 | * @brief Deserializes a set of pre-shared keys from a trits buffer 138 | * 139 | * @param trits[in] The trits buffer to deserialize from 140 | * @param psks[out] The set of pre-shared keys 141 | * 142 | * @return a status code 143 | */ 144 | retcode_t mam_psks_deserialize(trits_t* const trits, mam_psk_t_set_t* const psks); 145 | 146 | #ifdef __cplusplus 147 | } 148 | #endif 149 | 150 | #endif // __MAM_PSK_PSK_H__ 151 | 152 | /** @} */ 153 | -------------------------------------------------------------------------------- /mam/psk/tests/BUILD: -------------------------------------------------------------------------------- 1 | cc_test( 2 | name = "test_psk", 3 | timeout = "short", 4 | srcs = ["test_psk.c"], 5 | visibility = ["//visibility:private"], 6 | deps = [ 7 | "//mam/psk", 8 | "//mam/psk:mam_psk_t_set", 9 | "@org_iota_common//common/trinary:trit_tryte", 10 | "@unity", 11 | ], 12 | ) 13 | -------------------------------------------------------------------------------- /mam/psk/tests/test_psk.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https:github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by [ITSec Lab] 6 | * 7 | * Refer to the LICENSE file for licensing information 8 | */ 9 | 10 | #include 11 | 12 | #include 13 | 14 | #include "common/trinary/trit_tryte.h" 15 | #include "mam/psk/mam_psk_t_set.h" 16 | #include "mam/psk/psk.h" 17 | 18 | static void test_psks_serialization(void) { 19 | mam_psk_t_set_t psks_1 = NULL; 20 | mam_psk_t_set_t psks_2 = NULL; 21 | mam_psk_t psk; 22 | tryte_t id[MAM_PSK_ID_SIZE / 3]; 23 | tryte_t pre_shared_key[MAM_PSK_KEY_SIZE / 3]; 24 | 25 | for (size_t i = 0; i < 26; i++) { 26 | memset(id, 'A' + i, MAM_PSK_ID_SIZE / 3); 27 | trytes_to_trits(id, psk.id, MAM_PSK_ID_SIZE / 3); 28 | memset(pre_shared_key, 'A' + i, MAM_PSK_KEY_SIZE / 3); 29 | trytes_to_trits(pre_shared_key, psk.key, MAM_PSK_KEY_SIZE / 3); 30 | TEST_ASSERT(mam_psk_t_set_add(&psks_1, &psk) == RC_OK); 31 | } 32 | 33 | size_t size = mam_psks_serialized_size(psks_1); 34 | 35 | TEST_ASSERT_EQUAL_INT(size, 26 * (MAM_PSK_ID_SIZE + MAM_PSK_KEY_SIZE) + pb3_sizeof_size_t(26)); 36 | 37 | trits_t trits = trits_alloc(size); 38 | 39 | TEST_ASSERT(mam_psks_serialize(psks_1, &trits) == RC_OK); 40 | trits = trits_pickup_all(trits); 41 | 42 | TEST_ASSERT(mam_psks_deserialize(&trits, &psks_2) == RC_OK); 43 | 44 | TEST_ASSERT_TRUE(mam_psk_t_set_cmp(psks_1, psks_2)); 45 | 46 | trits_free(trits); 47 | mam_psks_destroy(&psks_1); 48 | mam_psks_destroy(&psks_2); 49 | } 50 | 51 | int main(void) { 52 | UNITY_BEGIN(); 53 | 54 | RUN_TEST(test_psks_serialization); 55 | 56 | return UNITY_END(); 57 | } 58 | -------------------------------------------------------------------------------- /mam/rep.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iotaledger-archive/mam.c/fca24aa8f98e535c6af9feea3394bdeea555d0d3/mam/rep.pdf -------------------------------------------------------------------------------- /mam/spec.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iotaledger-archive/mam.c/fca24aa8f98e535c6af9feea3394bdeea555d0d3/mam/spec.pdf -------------------------------------------------------------------------------- /mam/sponge/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//visibility:public"]) 2 | 3 | cc_library( 4 | name = "sponge", 5 | srcs = ["sponge.c"], 6 | hdrs = ["sponge.h"], 7 | deps = [ 8 | "//mam:defs", 9 | "//mam/trits", 10 | "//mam/trits:buffers", 11 | "//mam/troika", 12 | "@org_iota_common//common:errors", 13 | "@org_iota_common//common/trinary:add", 14 | ], 15 | ) 16 | 17 | cc_library( 18 | name = "spongos", 19 | srcs = ["spongos.c"], 20 | hdrs = ["spongos.h"], 21 | deps = [ 22 | ":sponge", 23 | ":spongos_types_hdr", 24 | ], 25 | ) 26 | 27 | cc_library( 28 | name = "spongos_types_hdr", 29 | hdrs = ["spongos_types.h"], 30 | deps = [ 31 | ":sponge", 32 | ], 33 | ) 34 | 35 | cc_library( 36 | name = "spongos_types", 37 | srcs = ["spongos_types.c"], 38 | hdrs = ["spongos_types.h"], 39 | deps = [ 40 | ":sponge", 41 | "//mam/pb3", 42 | ], 43 | ) 44 | -------------------------------------------------------------------------------- /mam/sponge/sponge.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https://github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by 6 | * [ITSec Lab] 7 | * 8 | * Refer to the LICENSE file for licensing information 9 | */ 10 | 11 | /** 12 | * @ingroup mam 13 | * 14 | * @{ 15 | * 16 | * @file 17 | * @brief 18 | * 19 | */ 20 | #ifndef __MAM_SPONGE_SPONGE_H__ 21 | #define __MAM_SPONGE_SPONGE_H__ 22 | 23 | #include "common/errors.h" 24 | #include "mam/defs.h" 25 | #include "mam/trits/trits.h" 26 | 27 | // Sponge state rate 28 | #define MAM_SPONGE_RATE 486 29 | // Sponge state control 30 | #define MAM_SPONGE_CONTROL 6 31 | // Sponge state capacity 32 | #define MAM_SPONGE_CAPACITY 237 33 | // Sponge state width 34 | #define MAM_SPONGE_WIDTH (MAM_SPONGE_RATE + MAM_SPONGE_CONTROL + MAM_SPONGE_CAPACITY) 35 | 36 | // Sponge fixed key size 37 | #define MAM_SPONGE_KEY_SIZE 243 38 | // Sponge fixed hash size 39 | #define MAM_SPONGE_HASH_SIZE 243 40 | // Sponge fixed MAC size 41 | #define MAM_SPONGE_MAC_SIZE 243 42 | 43 | // c2 control trit DATA 44 | #define MAM_SPONGE_CTL_DATA 0 45 | // c2 control trit HASH 46 | #define MAM_SPONGE_CTL_HASH 0 47 | // c2 control trit KEY 48 | #define MAM_SPONGE_CTL_KEY 1 49 | // c2 control trit PRN 50 | #define MAM_SPONGE_CTL_PRN 1 51 | // c2 control trit TEXT 52 | #define MAM_SPONGE_CTL_TEXT -1 53 | // c2 control trit MAC 54 | #define MAM_SPONGE_CTL_MAC -1 55 | 56 | #ifdef __cplusplus 57 | extern "C" { 58 | #endif 59 | 60 | /** 61 | * Sponge interface 62 | * 63 | * @field stack Additional memory used by the transformation function 64 | * @field state sponge state 65 | */ 66 | typedef struct sponge_s { 67 | trit_t state[MAM_SPONGE_WIDTH]; 68 | } mam_sponge_t; 69 | 70 | /** 71 | * Gets part (the first `rate` trits) of the sponge outer state 72 | * 73 | * @param sponge Sponge interface 74 | * 75 | * @return the trits 76 | */ 77 | trits_t mam_sponge_outer_trits(mam_sponge_t const *const sponge); 78 | 79 | /** 80 | * Sponge state initialization 81 | * 82 | * @param sponge Sponge interface 83 | */ 84 | void mam_sponge_init(mam_sponge_t *const sponge); 85 | 86 | /** 87 | * Internal state transformation 88 | * 89 | * @param sponge Sponge interface 90 | */ 91 | void mam_sponge_transform(mam_sponge_t *const sponge); 92 | 93 | /** 94 | * Fork (copy) sponge state. `fork` must be initialized 95 | * 96 | * @param sponge Sponge interface 97 | * @param fork Sponge interface 98 | */ 99 | void mam_sponge_fork(mam_sponge_t const *const sponge, mam_sponge_t *const fork); 100 | 101 | /** 102 | * Sponge absorption 103 | * 104 | * @param sponge Sponge interface 105 | * @param c2 Control trit encoding output data type 106 | * @param data Input data blocks 107 | */ 108 | void mam_sponge_absorb(mam_sponge_t *const sponge, trit_t const c2, trits_t data); 109 | /** 110 | * Absorb concatenation of `Xs[0]`..`Xs[n-1]` 111 | * 112 | * @param sponge Sponge interface 113 | * @param c2 Control trit encoding output data type 114 | * @param n Input data blocks count 115 | * @param data_blocks Input data blocks 116 | */ 117 | void mam_sponge_absorbn(mam_sponge_t *const sponge, trit_t const c2, size_t const n, trits_t const *const data_blocks); 118 | /** 119 | * Sponge squeezing 120 | * 121 | * @param sponge Sponge interface 122 | * @param c2 Control trit encoding output data type 123 | * @param squeezed Output data 124 | */ 125 | void mam_sponge_squeeze(mam_sponge_t *const sponge, trit_t const c2, trits_t squeezed); 126 | /** 127 | * Sponge AE encryption 128 | * 129 | * @param sponge Sponge interface 130 | * @param plaintext Input data 131 | * @param ciphertext Hash value 132 | */ 133 | void mam_sponge_encr(mam_sponge_t *const sponge, trits_t plaintext, trits_t ciphertext); 134 | /** 135 | * Sponge AE decryption 136 | * 137 | * @param sponge Sponge interface 138 | * @param ciphertext Hash value 139 | * @param plaintext Input data 140 | */ 141 | void mam_sponge_decr(mam_sponge_t *const sponge, trits_t ciphertext, trits_t plaintext); 142 | /** 143 | * Sponge hashing 144 | * 145 | * @param sponge Sponge interface 146 | * @param plaintext Input data 147 | * @param digest Hash value 148 | */ 149 | void mam_sponge_hash(mam_sponge_t *const sponge, trits_t const plaintext, trits_t digest); 150 | 151 | /** 152 | * Sponge hashing 153 | * 154 | * @param sponge Sponge interface 155 | * @param n Input data blocks count 156 | * @param plaintext_blocks Input data blocks 157 | * @param digest Hash value 158 | */ 159 | void mam_sponge_hashn(mam_sponge_t *const sponge, size_t const n, trits_t const *const plaintext_blocks, 160 | trits_t digest); 161 | 162 | #ifdef __cplusplus 163 | } 164 | #endif 165 | 166 | #endif // __MAM_SPONGE_SPONGE_H__ 167 | 168 | /** @} */ 169 | -------------------------------------------------------------------------------- /mam/sponge/spongos.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https://github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by 6 | * [ITSec Lab] 7 | * 8 | * Refer to the LICENSE file for licensing information 9 | */ 10 | 11 | #include 12 | 13 | #include "mam/sponge/sponge.h" 14 | #include "mam/sponge/spongos.h" 15 | 16 | static trits_t spongos_outer_trits(mam_spongos_t *const spongos) { 17 | return trits_drop(mam_sponge_outer_trits(&spongos->sponge), spongos->pos); 18 | } 19 | 20 | static void spongos_update(mam_spongos_t *const spongos, size_t const n) { 21 | spongos->pos += n; 22 | if (spongos->pos == MAM_SPONGE_RATE) { 23 | mam_spongos_commit(spongos); 24 | } 25 | } 26 | 27 | void mam_spongos_init(mam_spongos_t *const spongos) { 28 | mam_sponge_init(&spongos->sponge); 29 | spongos->pos = 0; 30 | } 31 | 32 | void mam_mam_spongos_fork(mam_spongos_t const *const spongos, mam_spongos_t *const fork) { 33 | mam_sponge_fork(&spongos->sponge, &fork->sponge); 34 | fork->pos = spongos->pos; 35 | } 36 | 37 | void mam_spongos_commit(mam_spongos_t *const spongos) { 38 | if (spongos->pos != 0) { 39 | mam_sponge_transform(&spongos->sponge); 40 | spongos->pos = 0; 41 | } 42 | } 43 | 44 | void mam_spongos_absorb(mam_spongos_t *const spongos, trits_t input) { 45 | for (size_t n = 0; !trits_is_empty(input); input = trits_drop(input, n)) { 46 | n = trits_copy_min(input, spongos_outer_trits(spongos)); 47 | spongos_update(spongos, n); 48 | } 49 | } 50 | 51 | void mam_spongos_absorbn(mam_spongos_t *const spongos, size_t const n, trits_t *const inputs) { 52 | for (size_t i = 0; i < n; i++) { 53 | mam_spongos_absorb(spongos, inputs[i]); 54 | } 55 | } 56 | 57 | void mam_spongos_squeeze(mam_spongos_t *const spongos, trits_t output) { 58 | for (size_t n = 0; !trits_is_empty(output); output = trits_drop(output, n)) { 59 | n = trits_copy_min(spongos_outer_trits(spongos), output); 60 | trits_set_zero(trits_take(spongos_outer_trits(spongos), n)); 61 | spongos_update(spongos, n); 62 | } 63 | } 64 | 65 | bool mam_spongos_squeeze_eq(mam_spongos_t *const spongos, trits_t expected_output) { 66 | bool r = true; 67 | trits_t y; 68 | 69 | for (size_t n = 0; !trits_is_empty(expected_output); expected_output = trits_drop(expected_output, n)) { 70 | y = trits_take_min(spongos_outer_trits(spongos), trits_size(expected_output)); 71 | n = trits_size(y); 72 | r = trits_cmp_eq(y, trits_take(expected_output, n)) && r; 73 | trits_set_zero(trits_take(spongos_outer_trits(spongos), n)); 74 | spongos_update(spongos, n); 75 | } 76 | 77 | return r; 78 | } 79 | 80 | void mam_spongos_hash(mam_spongos_t *const spongos, trits_t input, trits_t output) { 81 | mam_spongos_init(spongos); 82 | mam_spongos_absorb(spongos, input); 83 | mam_spongos_commit(spongos); 84 | mam_spongos_squeeze(spongos, output); 85 | } 86 | 87 | void mam_spongos_hashn(mam_spongos_t *const spongos, size_t const n, trits_t *inputs, trits_t output) { 88 | mam_spongos_init(spongos); 89 | mam_spongos_absorbn(spongos, n, inputs); 90 | mam_spongos_commit(spongos); 91 | mam_spongos_squeeze(spongos, output); 92 | } 93 | 94 | void mam_spongos_encr(mam_spongos_t *const spongos, trits_t plaintext, trits_t ciphertext) { 95 | for (size_t n = 0; !trits_is_empty(ciphertext); 96 | ciphertext = trits_drop(ciphertext, n), plaintext = trits_drop(plaintext, n)) { 97 | if (trits_is_same(plaintext, ciphertext)) 98 | n = trits_swap_add_min(plaintext, spongos_outer_trits(spongos)); 99 | else 100 | n = trits_copy_add_min(plaintext, spongos_outer_trits(spongos), ciphertext); 101 | spongos_update(spongos, n); 102 | } 103 | } 104 | 105 | void mam_spongos_decr(mam_spongos_t *const spongos, trits_t ciphertext, trits_t plaintext) { 106 | for (size_t n = 0; !trits_is_empty(plaintext); 107 | plaintext = trits_drop(plaintext, n), ciphertext = trits_drop(ciphertext, n)) { 108 | if (trits_is_same(ciphertext, plaintext)) 109 | n = trits_swap_sub_min(ciphertext, spongos_outer_trits(spongos)); 110 | else 111 | n = trits_copy_sub_min(ciphertext, spongos_outer_trits(spongos), plaintext); 112 | spongos_update(spongos, n); 113 | } 114 | } -------------------------------------------------------------------------------- /mam/sponge/spongos.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https://github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by 6 | * [ITSec Lab] 7 | * 8 | * Refer to the LICENSE file for licensing information 9 | */ 10 | 11 | /** 12 | * @ingroup mam 13 | * 14 | * @{ 15 | * 16 | * @file 17 | * @brief 18 | * 19 | */ 20 | #ifndef __MAM_SPONGE_SPONGOS_H__ 21 | #define __MAM_SPONGE_SPONGOS_H__ 22 | 23 | #include "mam/defs.h" 24 | #include "mam/sponge/sponge.h" 25 | #include "mam/sponge/spongos_types.h" 26 | #include "mam/trits/trits.h" 27 | 28 | #ifdef __cplusplus 29 | extern "C" { 30 | #endif 31 | 32 | /** 33 | * Initializes a spongos state 34 | * 35 | * @param spongos A spongos interface 36 | */ 37 | void mam_spongos_init(mam_spongos_t *const spongos); 38 | 39 | /** 40 | * Creates an equivalent spongos instance 41 | * 42 | * @param spongos A spongos interface 43 | * @param fork The fork 44 | */ 45 | void mam_mam_spongos_fork(mam_spongos_t const *const spongos, mam_spongos_t *const fork); 46 | 47 | /** 48 | * Commits changes in the rate part 49 | * 50 | * @param spongos A spongos interface 51 | */ 52 | void mam_spongos_commit(mam_spongos_t *const spongos); 53 | 54 | /** 55 | * Processes input data 56 | * 57 | * @param spongos A spongos interface 58 | * @param input Input data 59 | */ 60 | void mam_spongos_absorb(mam_spongos_t *const spongos, trits_t input); 61 | 62 | /** 63 | * Processes n inputs data 64 | * 65 | * @param spongos A spongos interface 66 | * @param n Number of input data 67 | * @param inputs Inputs data 68 | */ 69 | void mam_spongos_absorbn(mam_spongos_t *const spongos, size_t const n, trits_t *const inputs); 70 | 71 | /** 72 | * Generates output data 73 | * 74 | * @param spongos A spongos interface 75 | * @param output Output data 76 | */ 77 | void mam_spongos_squeeze(mam_spongos_t *const spongos, trits_t output); 78 | 79 | /** 80 | * Generates output data and check for equality with given output 81 | * 82 | * @param spongos A spongos interface 83 | * @param expected_output Expected output data 84 | */ 85 | bool mam_spongos_squeeze_eq(mam_spongos_t *const spongos, trits_t expected_output); 86 | 87 | /** 88 | * Hashes input data 89 | * 90 | * @param spongos A spongos interface 91 | * @param input Input data 92 | * @param output Output data 93 | */ 94 | void mam_spongos_hash(mam_spongos_t *const spongos, trits_t input, trits_t output); 95 | 96 | /** 97 | * Hashes n input data 98 | * 99 | * @param spongos A spongos interface 100 | * @param n Number of input data 101 | * @param inputs Inputs data 102 | * @param output Output data 103 | */ 104 | void mam_spongos_hashn(mam_spongos_t *const spongos, size_t const n, trits_t *inputs, trits_t output); 105 | 106 | /** 107 | * Encrypts plaintext 108 | * 109 | * @param spongos A spongos interface 110 | * @param plaintext Plaintext input 111 | * @param ciphertext Ciphertext output 112 | */ 113 | void mam_spongos_encr(mam_spongos_t *const spongos, trits_t plaintext, trits_t ciphertext); 114 | 115 | /** 116 | * Decrypts ciphertext 117 | * 118 | * @param spongos A spongos interface 119 | * @param ciphertext Ciphertext input 120 | * @param plaintext Plaintext output 121 | */ 122 | void mam_spongos_decr(mam_spongos_t *const spongos, trits_t ciphertext, trits_t plaintext); 123 | 124 | #ifdef __cplusplus 125 | } 126 | #endif 127 | 128 | #endif // __MAM_SPONGE_SPONGOS_H__ 129 | 130 | /** @} */ 131 | -------------------------------------------------------------------------------- /mam/sponge/spongos_types.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https://github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by 6 | * [ITSec Lab] 7 | * 8 | * Refer to the LICENSE file for licensing information 9 | */ 10 | 11 | #include "mam/sponge/spongos_types.h" 12 | #include "mam/pb3/pb3.h" 13 | 14 | size_t mam_spongos_serialized_size(mam_spongos_t const *const spongos) { 15 | return pb3_sizeof_size_t(spongos->pos) + MAM_SPONGE_WIDTH; 16 | } 17 | 18 | void mam_spongos_serialize(mam_spongos_t const *const spongos, trits_t *const trits) { 19 | pb3_encode_size_t(spongos->pos, trits); 20 | pb3_encode_ntrytes(trits_from_rep(MAM_SPONGE_WIDTH, spongos->sponge.state), trits); 21 | } 22 | 23 | retcode_t mam_spongos_deserialize(trits_t *const trits, mam_spongos_t *const spongos) { 24 | retcode_t err; 25 | ERR_BIND_RETURN(pb3_decode_size_t(&spongos->pos, trits), err); 26 | ERR_BIND_RETURN(pb3_decode_ntrytes(trits_from_rep(MAM_SPONGE_WIDTH, spongos->sponge.state), trits), err); 27 | return err; 28 | } 29 | -------------------------------------------------------------------------------- /mam/sponge/spongos_types.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https://github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by 6 | * [ITSec Lab] 7 | * 8 | * Refer to the LICENSE file for licensing information 9 | */ 10 | 11 | /** 12 | * @ingroup mam 13 | * 14 | * @{ 15 | * 16 | * @file 17 | * @brief 18 | * 19 | */ 20 | #ifndef __MAM_SPONGE_SPONGOS_TYPES_H__ 21 | #define __MAM_SPONGE_SPONGOS_TYPES_H__ 22 | 23 | #include "mam/defs.h" 24 | #include "mam/sponge/sponge.h" 25 | #include "mam/trits/trits.h" 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | typedef struct mam_spongos_s { 32 | mam_sponge_t sponge; 33 | size_t pos; 34 | } mam_spongos_t; 35 | 36 | size_t mam_spongos_serialized_size(mam_spongos_t const *const spongos); 37 | 38 | void mam_spongos_serialize(mam_spongos_t const *const spongos, trits_t *const trits); 39 | 40 | retcode_t mam_spongos_deserialize(trits_t *const trits, mam_spongos_t *const spongos); 41 | 42 | #ifdef __cplusplus 43 | } 44 | #endif 45 | 46 | #endif // __MAM_SPONGE_SPONGOS_TYPES_H__ 47 | 48 | /** @} */ 49 | -------------------------------------------------------------------------------- /mam/sponge/tests/BUILD: -------------------------------------------------------------------------------- 1 | cc_test( 2 | name = "test_sponge", 3 | timeout = "short", 4 | srcs = ["test_sponge.c"], 5 | deps = [ 6 | "//mam/sponge", 7 | "@unity", 8 | ], 9 | ) 10 | 11 | cc_test( 12 | name = "test_spongos", 13 | timeout = "short", 14 | srcs = ["test_spongos.c"], 15 | deps = [ 16 | "//mam/sponge:spongos", 17 | "//mam/sponge:spongos_types", 18 | "@unity", 19 | ], 20 | ) 21 | -------------------------------------------------------------------------------- /mam/sponge/tests/test_sponge.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https://github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by 6 | * [ITSec Lab] 7 | * 8 | * Refer to the LICENSE file for licensing information 9 | */ 10 | 11 | #include 12 | 13 | #include "mam/sponge/sponge.h" 14 | 15 | static void mam_sponge_hash_test(void) { 16 | mam_sponge_t sponge; 17 | 18 | MAM_TRITS_DEF(X0, MAM_SPONGE_RATE * 3); 19 | trits_t Xs[3], X; 20 | MAM_TRITS_DEF(Y1, 243); 21 | MAM_TRITS_DEF(Y2, 243); 22 | size_t n; 23 | X0 = MAM_TRITS_INIT(X0, MAM_SPONGE_RATE * 3); 24 | Y1 = MAM_TRITS_INIT(Y1, 243); 25 | Y2 = MAM_TRITS_INIT(Y2, 243); 26 | 27 | mam_sponge_init(&sponge); 28 | 29 | for (n = 0; n < MAM_SPONGE_RATE * 3; n += MAM_SPONGE_RATE / 2) { 30 | X = trits_take(X0, n); 31 | trits_set_zero(X); 32 | mam_sponge_hash(&sponge, X, Y1); 33 | 34 | if (0 && 0 < n) { 35 | trits_put1(X, trit_add(trits_get1(X), 1)); 36 | mam_sponge_hash(&sponge, X, Y2); 37 | trits_put1(X, trit_sub(trits_get1(X), 1)); 38 | TEST_ASSERT_TRUE(!trits_cmp_eq(Y1, Y2)); 39 | } 40 | 41 | Xs[0] = trits_take(X, n / 3); 42 | Xs[1] = trits_take(trits_drop(X, n / 3), n / 4); 43 | Xs[2] = trits_drop(X, n / 3 + n / 4); 44 | mam_sponge_hashn(&sponge, 3, Xs, Y2); 45 | TEST_ASSERT_TRUE(trits_cmp_eq(Y1, Y2)); 46 | } 47 | } 48 | 49 | static void sponge_ae_test(void) { 50 | mam_sponge_t sponge; 51 | 52 | #define MAM_SPONGE_TEST_MAX_K 1110 53 | size_t k, i; 54 | MAM_TRITS_DEF(K, MAM_SPONGE_KEY_SIZE); 55 | MAM_TRITS_DEF(X, MAM_SPONGE_TEST_MAX_K); 56 | MAM_TRITS_DEF(Y, MAM_SPONGE_TEST_MAX_K); 57 | MAM_TRITS_DEF(Z, MAM_SPONGE_TEST_MAX_K); 58 | size_t ks[] = {0, 1, 2, 3, 4, 5, 6, 242, 243, 244, 485, 486, 487, MAM_SPONGE_TEST_MAX_K, MAM_SPONGE_TEST_MAX_K + 1}; 59 | K = MAM_TRITS_INIT(K, MAM_SPONGE_KEY_SIZE); 60 | X = MAM_TRITS_INIT(X, MAM_SPONGE_TEST_MAX_K); 61 | Y = MAM_TRITS_INIT(Y, MAM_SPONGE_TEST_MAX_K); 62 | Z = MAM_TRITS_INIT(Z, MAM_SPONGE_TEST_MAX_K); 63 | 64 | /* init X */ 65 | for (i = 0; i < MAM_SPONGE_TEST_MAX_K / 3; ++i) { 66 | trits_put3(trits_drop(X, 3 * i), (tryte_t)((i % 27) - 13)); 67 | } 68 | /* init K */ 69 | trits_set_zero(K); 70 | trits_from_str(K, 71 | "NOPQRSTUVWXYZ9ABCDEFGHIJKLM" 72 | "NOPQRSTUVWXYZ9ABCDEFGHIJKLM" 73 | "NOPQRSTUVWXYZ9ABCDEFGHIJKLM"); 74 | mam_sponge_init(&sponge); 75 | mam_sponge_absorb(&sponge, MAM_SPONGE_CTL_KEY, K); 76 | mam_sponge_squeeze(&sponge, MAM_SPONGE_CTL_PRN, K); 77 | 78 | for (i = 0; (k = ks[i++]) <= MAM_SPONGE_TEST_MAX_K;) { 79 | X = MAM_TRITS_INIT(X, k); 80 | Y = MAM_TRITS_INIT(Y, k); 81 | Z = MAM_TRITS_INIT(Z, k); 82 | 83 | mam_sponge_init(&sponge); 84 | mam_sponge_absorb(&sponge, MAM_SPONGE_CTL_KEY, K); 85 | mam_sponge_encr(&sponge, X, Y); /* Y=E(X) */ 86 | 87 | mam_sponge_init(&sponge); 88 | mam_sponge_absorb(&sponge, MAM_SPONGE_CTL_KEY, K); 89 | mam_sponge_decr(&sponge, Y, Z); /* Z=D(E(X)) */ 90 | TEST_ASSERT_TRUE(trits_cmp_eq(X, Z)); 91 | 92 | mam_sponge_init(&sponge); 93 | mam_sponge_absorb(&sponge, MAM_SPONGE_CTL_KEY, K); 94 | mam_sponge_encr(&sponge, Z, Z); /* Z=E(Z=X) */ 95 | TEST_ASSERT_TRUE(trits_cmp_eq(Y, Z)); 96 | 97 | mam_sponge_init(&sponge); 98 | mam_sponge_absorb(&sponge, MAM_SPONGE_CTL_KEY, K); 99 | mam_sponge_decr(&sponge, Z, Z); /* Z=D(Z=E(X)) */ 100 | TEST_ASSERT_TRUE(trits_cmp_eq(X, Z)); 101 | } 102 | 103 | #undef MAM_SPONGE_TEST_MAX_K 104 | } 105 | 106 | int main(void) { 107 | UNITY_BEGIN(); 108 | 109 | RUN_TEST(sponge_ae_test); 110 | RUN_TEST(mam_sponge_hash_test); 111 | 112 | return UNITY_END(); 113 | } 114 | -------------------------------------------------------------------------------- /mam/sponge/tests/test_spongos.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https://github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by 6 | * [ITSec Lab] 7 | * 8 | * Refer to the LICENSE file for licensing information 9 | */ 10 | 11 | #include 12 | 13 | #include 14 | 15 | #include "mam/sponge/spongos.h" 16 | #include "mam/sponge/spongos_types.h" 17 | 18 | static void mam_spongos_test(void) { 19 | mam_spongos_t spongos; 20 | mam_spongos_t deserialized_spongos; 21 | 22 | mam_spongos_init(&spongos); 23 | 24 | MAM_TRITS_DEF(x, 243); 25 | MAM_TRITS_DEF(y, 243); 26 | MAM_TRITS_DEF(z, 243); 27 | x = MAM_TRITS_INIT(x, 243); 28 | y = MAM_TRITS_INIT(y, 243); 29 | z = MAM_TRITS_INIT(z, 243); 30 | 31 | trits_set_zero(x); 32 | 33 | mam_spongos_init(&spongos); 34 | mam_spongos_absorb(&spongos, x); 35 | mam_spongos_commit(&spongos); 36 | mam_spongos_squeeze(&spongos, y); 37 | 38 | mam_spongos_init(&spongos); 39 | mam_spongos_absorb(&spongos, x); 40 | mam_spongos_commit(&spongos); 41 | mam_spongos_encr(&spongos, x, z); 42 | 43 | TEST_ASSERT_TRUE(trits_cmp_eq(y, z)); 44 | 45 | mam_spongos_init(&spongos); 46 | mam_spongos_absorb(&spongos, x); 47 | mam_spongos_commit(&spongos); 48 | mam_spongos_decr(&spongos, z, z); 49 | MAM_TRITS_DEF(spongos_trits, mam_spongos_serialized_size(&spongos)); 50 | spongos_trits = MAM_TRITS_INIT(spongos_trits, mam_spongos_serialized_size(&spongos)); 51 | mam_spongos_serialize(&spongos, &spongos_trits); 52 | spongos_trits = trits_pickup(spongos_trits, mam_spongos_serialized_size(&spongos)); 53 | memset(deserialized_spongos.sponge.state, 0, MAM_SPONGE_WIDTH); 54 | TEST_ASSERT_EQUAL(RC_OK, mam_spongos_deserialize(&spongos_trits, &deserialized_spongos)); 55 | 56 | TEST_ASSERT_EQUAL_INT(spongos.pos, deserialized_spongos.pos); 57 | TEST_ASSERT_EQUAL_MEMORY(spongos.sponge.state, deserialized_spongos.sponge.state, MAM_SPONGE_WIDTH); 58 | 59 | TEST_ASSERT_TRUE(trits_cmp_eq(x, z)); 60 | } 61 | 62 | int main(void) { 63 | UNITY_BEGIN(); 64 | 65 | RUN_TEST(mam_spongos_test); 66 | 67 | return UNITY_END(); 68 | } 69 | -------------------------------------------------------------------------------- /mam/trits/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//visibility:public"]) 2 | 3 | cc_library( 4 | name = "buffers", 5 | srcs = ["buffers.c"], 6 | hdrs = ["buffers.h"], 7 | deps = [ 8 | ":trits", 9 | "//mam:defs", 10 | ], 11 | ) 12 | 13 | cc_library( 14 | name = "trits", 15 | srcs = ["trits.c"], 16 | hdrs = ["trits.h"], 17 | deps = [ 18 | "//mam:defs", 19 | "@org_iota_common//common:errors", 20 | "@org_iota_common//common/trinary:trit_long", 21 | "@org_iota_common//common/trinary:trit_tryte", 22 | ], 23 | ) 24 | -------------------------------------------------------------------------------- /mam/trits/buffers.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https://github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by 6 | * [ITSec Lab] 7 | * 8 | * Refer to the LICENSE file for licensing information 9 | */ 10 | 11 | #include "mam/trits/buffers.h" 12 | 13 | buffers_t buffers_init(size_t const count, trits_t const *const trits) { 14 | buffers_t buffers; 15 | 16 | buffers.head = trits_null(); 17 | buffers.count = count; 18 | buffers.tail = (trits_t *const)trits; 19 | 20 | return buffers; 21 | } 22 | 23 | size_t buffers_size(buffers_t buffers) { 24 | size_t m = 0; 25 | 26 | for (; !buffers_is_empty(buffers);) { 27 | m += trits_size(buffers.head); 28 | buffers.head = trits_null(); 29 | 30 | if (0 < buffers.count) { 31 | buffers.head = *buffers.tail++; 32 | buffers.count--; 33 | } 34 | } 35 | 36 | return m; 37 | } 38 | 39 | size_t buffers_copy_to(buffers_t *const buffers, trits_t trits) { 40 | size_t k, m = 0; 41 | 42 | for (; !trits_is_empty(trits) && !buffers_is_empty(*buffers);) { 43 | k = trits_copy_min(buffers->head, trits); 44 | buffers->head = trits_drop(buffers->head, k); 45 | trits = trits_drop(trits, k); 46 | m += k; 47 | 48 | if (trits_is_empty(buffers->head) && (0 < buffers->count)) { 49 | buffers->head = *buffers->tail++; 50 | buffers->count--; 51 | } 52 | } 53 | 54 | return m; 55 | } 56 | -------------------------------------------------------------------------------- /mam/trits/buffers.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https://github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by 6 | * [ITSec Lab] 7 | * 8 | * Refer to the LICENSE file for licensing information 9 | */ 10 | 11 | /** 12 | * @ingroup mam 13 | * 14 | * @{ 15 | * 16 | * @file 17 | * @brief 18 | * 19 | */ 20 | #ifndef __MAM_TRITS_BUFFERS_H__ 21 | #define __MAM_TRITS_BUFFERS_H__ 22 | 23 | #include "mam/defs.h" 24 | #include "mam/trits/trits.h" 25 | 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | 30 | typedef struct buffers_s { 31 | trits_t head; 32 | trits_t *tail; 33 | size_t count; 34 | } buffers_t; 35 | 36 | /** 37 | * Init buffers with empty head 38 | * 39 | * @param count The number of trit arrays 40 | * @param trits The trit arrays 41 | * 42 | * @return the buffers 43 | */ 44 | buffers_t buffers_init(size_t const count, trits_t const *const trits); 45 | 46 | /** 47 | * Check whether head is empty and there is no tail 48 | * However if the tail buffers consist of empty buffers only it will _not_ 49 | * be considered empty! 50 | * 51 | * @param buffers The buffers 52 | * 53 | * @return true if empty, false otherwise 54 | */ 55 | static inline bool buffers_is_empty(buffers_t const buffers) { 56 | return trits_is_empty(buffers.head) && (buffers.count == 0); 57 | } 58 | 59 | /** 60 | * Sum of head and tail buffers sizes 61 | * 62 | * @param buffers The buffers 63 | * 64 | * @return the size of the buffers 65 | */ 66 | size_t buffers_size(buffers_t buffers); 67 | 68 | /** 69 | * Copy buffers `*buffers` to a destination `trits` 70 | * 71 | * @param buffers The buffers 72 | * @param trits The trits 73 | * 74 | * @return the number of trits copied 75 | */ 76 | size_t buffers_copy_to(buffers_t *const buffers, trits_t trits); 77 | 78 | #ifdef __cplusplus 79 | } 80 | #endif 81 | 82 | #endif // __MAM_TRITS_BUFFERS_H__ 83 | 84 | /** @} */ 85 | -------------------------------------------------------------------------------- /mam/trits/tests/BUILD: -------------------------------------------------------------------------------- 1 | cc_test( 2 | name = "test_trits", 3 | timeout = "short", 4 | srcs = ["test_trits.c"], 5 | deps = [ 6 | "//mam/trits", 7 | "@unity", 8 | ], 9 | ) 10 | -------------------------------------------------------------------------------- /mam/trits/tests/test_trits.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https://github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by 6 | * [ITSec Lab] 7 | * 8 | * Refer to the LICENSE file for licensing information 9 | */ 10 | 11 | #include 12 | 13 | #include 14 | 15 | #include "mam/trits/trits.h" 16 | 17 | static void trits_put_get_test(void) { 18 | trit_t t0, t; 19 | size_t i; 20 | 21 | MAM_TRITS_DEF(x, 1); 22 | 23 | x = MAM_TRITS_INIT(x, 1); 24 | trits_set_zero(x); 25 | 26 | for (i = 0; i < 1; ++i) { 27 | trits_put1(x, t0 = -1); 28 | t = trits_get1(x); 29 | TEST_ASSERT_TRUE(t == t0); 30 | 31 | trits_put1(x, t0 = 0); 32 | t = trits_get1(x); 33 | TEST_ASSERT_TRUE(t == t0); 34 | 35 | trits_put1(x, t0 = 1); 36 | t = trits_get1(x); 37 | TEST_ASSERT_TRUE(t == t0); 38 | 39 | x = trits_drop(x, 1); 40 | } 41 | } 42 | 43 | static void trits_add_sub_test(void) { 44 | trit_t x, x1, x2, s1, s2, y1, y2; 45 | size_t ix, is; 46 | trit_t const ts[3] = {-1, 0, 1}; 47 | 48 | for (ix = 0; ix < 3; ++ix) 49 | for (is = 0; is < 3; ++is) { 50 | x = ts[ix]; 51 | 52 | s1 = ts[is]; 53 | y1 = trit_add(x, s1); 54 | s1 = x; 55 | 56 | y2 = x; 57 | s2 = ts[is]; 58 | trit_swap_add(&y2, &s2); 59 | 60 | TEST_ASSERT_TRUE(s1 == s2); 61 | TEST_ASSERT_TRUE(y1 == y2); 62 | 63 | s1 = ts[is]; 64 | x1 = trit_sub(y1, s1); 65 | s1 = x1; 66 | 67 | x2 = y2; 68 | s2 = ts[is]; 69 | trit_swap_sub(&x2, &s2); 70 | 71 | TEST_ASSERT_TRUE(s1 == s2); 72 | TEST_ASSERT_TRUE(x == x1); 73 | TEST_ASSERT_TRUE(x == x2); 74 | } 75 | } 76 | 77 | static bool trits_trytes(trits_t x, char *s, char *t) { 78 | bool r = true; 79 | size_t n = trits_size(x) / 3; 80 | trits_t y; 81 | trint1_t s1; 82 | trint3_t s3; 83 | trint9_t s9; 84 | trint18_t s18; 85 | 86 | MAM_ASSERT(0 == (trits_size(x) % 3)); 87 | 88 | trits_from_str(x, s); 89 | 90 | for (y = x; !trits_is_empty(y); y = trits_drop(y, 1)) { 91 | s1 = trits_get1(y); 92 | trits_put1(y, 0); 93 | trits_put1(y, s1); 94 | r = r && (s1 == trits_get1(y)); 95 | } 96 | trits_to_str(x, t); 97 | r = r && (0 == memcmp(s, t, n)); 98 | 99 | for (y = x; 3 <= trits_size(y); y = trits_drop(y, 3)) { 100 | s3 = trits_get3(y); 101 | trits_put3(y, 0); 102 | trits_put3(y, s3); 103 | r = r && (s3 == trits_get3(y)); 104 | } 105 | trits_to_str(x, t); 106 | r = r && (0 == memcmp(s, t, n)); 107 | 108 | for (y = x; 9 <= trits_size(y); y = trits_drop(y, 9)) { 109 | s9 = trits_get9(y); 110 | trits_put9(y, 0); 111 | trits_put9(y, s9); 112 | r = r && (s9 == trits_get9(y)); 113 | } 114 | trits_to_str(x, t); 115 | r = r && (0 == memcmp(s, t, n)); 116 | 117 | for (y = x; 18 <= trits_size(y); y = trits_drop(y, 18)) { 118 | s18 = trits_get18(y); 119 | trits_put18(y, 0); 120 | trits_put18(y, s18); 121 | r = r && (s18 == trits_get18(y)); 122 | } 123 | trits_to_str(x, t); 124 | r = r && (0 == memcmp(s, t, n)); 125 | 126 | return r; 127 | } 128 | 129 | static void trits_test(void) { 130 | char s[6 * 4 + 1] = "KLMNOPQABCDWXYZ9ZA9NZA9N"; 131 | char t[6 * 4]; 132 | trits_t x; 133 | 134 | MAM_TRITS_DEF(y, 3 * 6 * 4); 135 | y = MAM_TRITS_INIT(y, 3 * 6 * 4); 136 | 137 | for (size_t n = 0; n <= 6 * 4; ++n) { 138 | x = trits_take(y, 3 * n); 139 | TEST_ASSERT_TRUE(trits_trytes(x, s, t)); 140 | } 141 | } 142 | 143 | int main(void) { 144 | UNITY_BEGIN(); 145 | 146 | RUN_TEST(trits_put_get_test); 147 | RUN_TEST(trits_add_sub_test); 148 | RUN_TEST(trits_test); 149 | 150 | return UNITY_END(); 151 | } 152 | -------------------------------------------------------------------------------- /mam/troika/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//visibility:public"]) 2 | 3 | cc_library( 4 | name = "troika", 5 | srcs = ["troika.c"], 6 | hdrs = ["troika.h"], 7 | deps = [ 8 | "//mam:defs", 9 | "//mam/trits", 10 | "@org_iota_common//common:stdint", 11 | "@org_iota_common//common/crypto/ftroika", 12 | "@org_iota_common//common/crypto/troika", 13 | ], 14 | ) 15 | -------------------------------------------------------------------------------- /mam/troika/tests/BUILD: -------------------------------------------------------------------------------- 1 | cc_test( 2 | name = "test_troika", 3 | timeout = "short", 4 | srcs = ["test_troika.c"], 5 | deps = [ 6 | "//mam/troika", 7 | "@org_iota_common//common/trinary:trit_tryte", 8 | "@unity", 9 | ], 10 | ) 11 | -------------------------------------------------------------------------------- /mam/troika/tests/test_troika.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https://github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by 6 | * [ITSec Lab] 7 | * 8 | * Refer to the LICENSE file for licensing information 9 | */ 10 | 11 | #include 12 | 13 | #include "common/defs.h" 14 | #include "common/trinary/trit_tryte.h" 15 | #include "mam/troika/troika.h" 16 | 17 | #define EXPECTED_OUTPUT \ 18 | "IONONZOXVGTNGVEOCXPUIJU9LTJPI9LSJJTPABX9QQVPGMGZSVGOMTOGXJXRGMBODKKKBCNCXQ" \ 19 | "UXWMCIIGAYEIOYWGHRLPFCRB9AJZZOQOUBUVWKW9I9CDHCEYPQZNTE9TZAKFRZLSLANRUPNVLO" \ 20 | "LTIWHCKBAWSGTPMFCPW9IWV9HEJGQQUXBJTPXDFLKYIWSCHQIVPUBLDBARZLQNMNQASAPST9LP" \ 21 | "SGDCIUGWJCIQQKJCLBGFU" 22 | 23 | #define TEST_TROIKA_STATE_SIZE 729 24 | 25 | static void troika_test(void) { 26 | trit_t state[TEST_TROIKA_STATE_SIZE]; 27 | tryte_t output_trytes[TEST_TROIKA_STATE_SIZE / NUMBER_OF_TRITS_IN_A_TRYTE]; 28 | memset(state, 0, TEST_TROIKA_STATE_SIZE * sizeof(trit_t)); 29 | mam_ftroika_transform(state, TEST_TROIKA_STATE_SIZE); 30 | trits_to_trytes(state, output_trytes, TEST_TROIKA_STATE_SIZE); 31 | TEST_ASSERT_EQUAL_MEMORY(EXPECTED_OUTPUT, output_trytes, TEST_TROIKA_STATE_SIZE / NUMBER_OF_TRITS_IN_A_TRYTE); 32 | } 33 | 34 | int main(void) { 35 | UNITY_BEGIN(); 36 | 37 | RUN_TEST(troika_test); 38 | 39 | return UNITY_END(); 40 | } 41 | -------------------------------------------------------------------------------- /mam/troika/troika.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https://github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by 6 | * [ITSec Lab] 7 | * 8 | * Refer to the LICENSE file for licensing information 9 | */ 10 | 11 | #include "mam/troika/troika.h" 12 | #include "mam/trits/trits.h" 13 | 14 | void mam_ftroika_transform(trit_t *const state, size_t state_size) { 15 | size_t i; 16 | t27_t fstate[SLICES]; 17 | for (i = 0; i != state_size; ++i) { 18 | state[i] += 1; 19 | } 20 | state_to_fstate(state, fstate); 21 | ftroika_permutation(fstate, MAM_TROIKA_NUM_ROUNDS); 22 | fstate_to_state(fstate, state); 23 | for (i = 0; i != state_size; ++i) { 24 | state[i] -= 1; 25 | } 26 | } 27 | 28 | void mam_troika_transform(trit_t *const state, size_t state_size) { 29 | size_t i; 30 | for (i = 0; i != state_size; ++i) { 31 | state[i] += 1; 32 | } 33 | troika_permutation(state, MAM_TROIKA_NUM_ROUNDS); 34 | for (i = 0; i != state_size; ++i) { 35 | state[i] -= 1; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /mam/troika/troika.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https://github.com/iotaledger/entangled 4 | * MAM is based on an original implementation & specification by apmi.bsu.by 5 | * [ITSec Lab] 6 | * 7 | * Refer to the LICENSE file for licensing information 8 | */ 9 | 10 | /** 11 | * @ingroup mam 12 | * 13 | * @{ 14 | * 15 | * @file 16 | * @brief 17 | * 18 | */ 19 | #ifndef __MAM_TROIKA_TROIKA_H__ 20 | #define __MAM_TROIKA_TROIKA_H__ 21 | 22 | #include "common/crypto/ftroika/ftroika.h" 23 | #include "common/crypto/troika/troika.h" 24 | #include "mam/defs.h" 25 | 26 | #define MAM_TROIKA_NUM_ROUNDS 24 27 | 28 | void mam_ftroika_transform(trit_t *const state, size_t state_size); 29 | void mam_troika_transform(trit_t *const state, size_t state_size); 30 | 31 | #endif //__MAM_TROIKA_TROIKA_H__ 32 | 33 | /** @} */ 34 | -------------------------------------------------------------------------------- /mam/wots/BUILD: -------------------------------------------------------------------------------- 1 | cc_library( 2 | name = "wots", 3 | srcs = ["wots.c"], 4 | hdrs = ["wots.h"], 5 | visibility = ["//visibility:public"], 6 | deps = [ 7 | "//mam:defs", 8 | "//mam/prng", 9 | "//mam/sponge:spongos", 10 | "//mam/trits", 11 | "@org_iota_common//common:errors", 12 | "@org_iota_common//utils:memset_safe", 13 | ], 14 | ) 15 | -------------------------------------------------------------------------------- /mam/wots/tests/BUILD: -------------------------------------------------------------------------------- 1 | cc_test( 2 | name = "test_wots", 3 | timeout = "short", 4 | srcs = ["test_wots.c"], 5 | visibility = ["//visibility:private"], 6 | deps = [ 7 | "//mam/wots", 8 | "@unity", 9 | ], 10 | ) 11 | -------------------------------------------------------------------------------- /mam/wots/tests/test_wots.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https://github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by [ITSec Lab] 6 | * 7 | * Refer to the LICENSE file for licensing information 8 | */ 9 | 10 | #include 11 | 12 | #include "mam/wots/wots.h" 13 | 14 | static void mam_wots_test(void) { 15 | mam_prng_t prng; 16 | mam_wots_t wots; 17 | 18 | MAM_TRITS_DEF(N, 18); 19 | MAM_TRITS_DEF(pk, MAM_WOTS_PUBLIC_KEY_SIZE); 20 | MAM_TRITS_DEF(recovered_pk, MAM_WOTS_PUBLIC_KEY_SIZE); 21 | MAM_TRITS_DEF(H, MAM_WOTS_HASH_SIZE); 22 | MAM_TRITS_DEF(sig, MAM_WOTS_SIGNATURE_SIZE); 23 | MAM_TRITS_DEF(K, MAM_PRNG_SECRET_KEY_SIZE); 24 | 25 | N = MAM_TRITS_INIT(N, 18); 26 | pk = MAM_TRITS_INIT(pk, MAM_WOTS_PUBLIC_KEY_SIZE); 27 | recovered_pk = MAM_TRITS_INIT(recovered_pk, MAM_WOTS_PUBLIC_KEY_SIZE); 28 | H = MAM_TRITS_INIT(H, MAM_WOTS_HASH_SIZE); 29 | sig = MAM_TRITS_INIT(sig, MAM_WOTS_SIGNATURE_SIZE); 30 | K = MAM_TRITS_INIT(K, MAM_PRNG_SECRET_KEY_SIZE); 31 | 32 | trits_set_zero(N); 33 | trits_set_zero(H); 34 | trits_set_zero(K); 35 | 36 | mam_prng_init(&prng, K); 37 | mam_wots_reset(&wots); 38 | mam_prng_gen(&prng, 7, N, H); 39 | mam_wots_gen_sk(&wots, &prng, N); 40 | mam_wots_gen_pk(&wots, pk); 41 | mam_wots_sign(&wots, H, sig); 42 | 43 | mam_wots_recover(H, sig, recovered_pk); 44 | TEST_ASSERT_TRUE(trits_cmp_eq(pk, recovered_pk)); 45 | 46 | trits_put1(H, trit_add(trits_get1(H), 1)); 47 | mam_wots_recover(H, sig, recovered_pk); 48 | TEST_ASSERT_FALSE(trits_cmp_eq(pk, recovered_pk)); 49 | trits_put1(H, trit_sub(trits_get1(H), 1)); 50 | 51 | trits_put1(sig, trit_add(trits_get1(sig), 1)); 52 | mam_wots_recover(H, sig, recovered_pk); 53 | TEST_ASSERT_FALSE(trits_cmp_eq(pk, recovered_pk)); 54 | trits_put1(sig, trit_sub(trits_get1(sig), 1)); 55 | 56 | trits_put1(pk, trit_add(trits_get1(pk), 1)); 57 | mam_wots_recover(H, sig, recovered_pk); 58 | TEST_ASSERT_FALSE(trits_cmp_eq(pk, recovered_pk)); 59 | trits_put1(pk, trit_sub(trits_get1(pk), 1)); 60 | } 61 | 62 | int main(void) { 63 | UNITY_BEGIN(); 64 | 65 | RUN_TEST(mam_wots_test); 66 | 67 | return UNITY_END(); 68 | } 69 | -------------------------------------------------------------------------------- /mam/wots/wots.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https://github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by [ITSec Lab] 6 | * 7 | * Refer to the LICENSE file for licensing information 8 | */ 9 | 10 | #include "mam/wots/wots.h" 11 | 12 | /* 13 | * Private functions 14 | */ 15 | 16 | typedef enum wots_hash_operation_e { WOTS_HASH_SIGN, WOTS_HASH_RECOVER } wots_hash_operation_t; 17 | 18 | static void wots_hash_sign_or_recover(mam_spongos_t *const spongos, trits_t const hash, trits_t signature, 19 | wots_hash_operation_t const operation) { 20 | size_t i; 21 | trint9_t t = 0; 22 | trint3_t j, h; 23 | trits_t signature_part; 24 | 25 | for (i = 0; i < MAM_WOTS_PRIVATE_KEY_PART_COUNT - 3; ++i) { 26 | signature_part = trits_take(signature, MAM_WOTS_PRIVATE_KEY_PART_SIZE); 27 | signature = trits_drop(signature, MAM_WOTS_PRIVATE_KEY_PART_SIZE); 28 | 29 | h = trits_get3(trits_drop(hash, i * 3)); 30 | t += h; 31 | h = (operation == WOTS_HASH_SIGN ? h : -h); 32 | 33 | for (j = -13; j < h; ++j) { 34 | mam_spongos_hash(spongos, signature_part, signature_part); 35 | } 36 | } 37 | 38 | t = -t; 39 | for (; i < MAM_WOTS_PRIVATE_KEY_PART_COUNT; ++i) { 40 | signature_part = trits_take(signature, MAM_WOTS_PRIVATE_KEY_PART_SIZE); 41 | signature = trits_drop(signature, MAM_WOTS_PRIVATE_KEY_PART_SIZE); 42 | 43 | h = MAM_MODS(t, 19683, 27); 44 | t = MAM_DIVS(t, 19683, 27); 45 | h = (operation == WOTS_HASH_SIGN ? h : -h); 46 | 47 | for (j = -13; j < h; ++j) { 48 | mam_spongos_hash(spongos, signature_part, signature_part); 49 | } 50 | } 51 | } 52 | 53 | /* 54 | * Public functions 55 | */ 56 | 57 | retcode_t mam_wots_gen_pk(mam_wots_t const *const wots, trits_t public_key) { 58 | mam_spongos_t spongos; 59 | mam_spongos_t spongos_part; 60 | trit_t private_key_part[MAM_WOTS_PRIVATE_KEY_PART_SIZE]; 61 | 62 | if (wots == NULL) { 63 | return RC_NULL_PARAM; 64 | } 65 | 66 | if (trits_size(public_key) != MAM_WOTS_PUBLIC_KEY_SIZE) { 67 | return RC_INVALID_PARAM; 68 | } 69 | 70 | mam_spongos_init(&spongos_part); 71 | for (size_t i = 0; i < MAM_WOTS_PRIVATE_KEY_PART_COUNT; ++i) { 72 | memcpy(private_key_part, wots->private_key + MAM_WOTS_PRIVATE_KEY_PART_SIZE * i, MAM_WOTS_PRIVATE_KEY_PART_SIZE); 73 | for (size_t j = 0; j < 26; ++j) { 74 | mam_spongos_hash(&spongos, trits_from_rep(MAM_WOTS_PRIVATE_KEY_PART_SIZE, private_key_part), 75 | trits_from_rep(MAM_WOTS_PRIVATE_KEY_PART_SIZE, private_key_part)); 76 | } 77 | mam_spongos_absorb(&spongos_part, trits_from_rep(MAM_WOTS_PRIVATE_KEY_PART_SIZE, private_key_part)); 78 | } 79 | mam_spongos_commit(&spongos_part); 80 | mam_spongos_squeeze(&spongos_part, public_key); 81 | 82 | return RC_OK; 83 | } 84 | 85 | retcode_t mam_wots_sign(mam_wots_t const *const wots, trits_t const hash, trits_t signature) { 86 | mam_spongos_t spongos; 87 | 88 | if (wots == NULL) { 89 | return RC_NULL_PARAM; 90 | } 91 | 92 | if (trits_size(hash) != MAM_WOTS_HASH_SIZE || trits_size(signature) != MAM_WOTS_SIGNATURE_SIZE) { 93 | return RC_INVALID_PARAM; 94 | } 95 | 96 | memcpy(trits_begin(signature), wots->private_key, MAM_WOTS_PRIVATE_KEY_SIZE); 97 | wots_hash_sign_or_recover(&spongos, hash, signature, WOTS_HASH_SIGN); 98 | 99 | return RC_OK; 100 | } 101 | 102 | retcode_t mam_wots_recover(trits_t const hash, trits_t const signature, trits_t public_key) { 103 | mam_spongos_t spongos; 104 | trit_t sig_pks[MAM_WOTS_PRIVATE_KEY_SIZE]; 105 | 106 | if (trits_size(hash) != MAM_WOTS_HASH_SIZE || trits_size(signature) != MAM_WOTS_SIGNATURE_SIZE || 107 | trits_size(public_key) != MAM_WOTS_PUBLIC_KEY_SIZE) { 108 | return RC_INVALID_PARAM; 109 | } 110 | 111 | memcpy(sig_pks, trits_begin(signature), MAM_WOTS_SIGNATURE_SIZE); 112 | wots_hash_sign_or_recover(&spongos, hash, trits_from_rep(MAM_WOTS_PRIVATE_KEY_SIZE, sig_pks), WOTS_HASH_RECOVER); 113 | mam_spongos_hash(&spongos, trits_from_rep(MAM_WOTS_PRIVATE_KEY_SIZE, sig_pks), public_key); 114 | 115 | return RC_OK; 116 | } 117 | -------------------------------------------------------------------------------- /mam/wots/wots.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 IOTA Stiftung 3 | * https://github.com/iotaledger/entangled 4 | * 5 | * MAM is based on an original implementation & specification by apmi.bsu.by [ITSec Lab] 6 | * 7 | * Refer to the LICENSE file for licensing information 8 | */ 9 | 10 | /** 11 | * @ingroup mam 12 | * 13 | * @{ 14 | * 15 | * @file 16 | * @brief The WOTS layer supports Winternitz One-Time Signatures 17 | * 18 | */ 19 | #ifndef __MAM_WOTS_WOTS_H__ 20 | #define __MAM_WOTS_WOTS_H__ 21 | 22 | #include "common/errors.h" 23 | #include "mam/defs.h" 24 | #include "mam/prng/prng.h" 25 | #include "mam/sponge/spongos.h" 26 | #include "mam/trits/trits.h" 27 | #include "utils/memset_safe.h" 28 | 29 | /** @brief Size of a WOTS public key */ 30 | #define MAM_WOTS_PUBLIC_KEY_SIZE 243 31 | /** @brief Size of a WOTS private key part */ 32 | #define MAM_WOTS_PRIVATE_KEY_PART_SIZE 162 33 | /** @brief Number of parts in a WOTS private key */ 34 | #define MAM_WOTS_PRIVATE_KEY_PART_COUNT 81 35 | /** @brief Size of a WOTS private key */ 36 | #define MAM_WOTS_PRIVATE_KEY_SIZE (MAM_WOTS_PRIVATE_KEY_PART_SIZE * MAM_WOTS_PRIVATE_KEY_PART_COUNT) 37 | /** @brief Size of a WOTS signed hash */ 38 | #define MAM_WOTS_HASH_SIZE 234 39 | /** @brief Size of a WOTS signature */ 40 | #define MAM_WOTS_SIGNATURE_SIZE MAM_WOTS_PRIVATE_KEY_SIZE 41 | 42 | #ifdef __cplusplus 43 | extern "C" { 44 | #endif 45 | 46 | typedef struct mam_wots_s { 47 | trit_t private_key[MAM_WOTS_PRIVATE_KEY_SIZE]; 48 | } mam_wots_t; 49 | 50 | /** 51 | * @brief Safely resets a WOTS private key 52 | * 53 | * @param[out] wots The WOTS private key 54 | * 55 | * @return a status code 56 | */ 57 | static inline retcode_t mam_wots_reset(mam_wots_t *const wots) { 58 | if (wots == NULL) { 59 | return RC_NULL_PARAM; 60 | } 61 | 62 | memset_safe(wots->private_key, MAM_WOTS_PRIVATE_KEY_SIZE, 0, MAM_WOTS_PRIVATE_KEY_SIZE); 63 | 64 | return RC_OK; 65 | } 66 | 67 | /** 68 | * @brief Generates a WOTS private key with five nonces 69 | * 70 | * @param[out] wots The WOTS private key 71 | * @param[in] prng A PRNG 72 | * @param[in] nonce1 The first nonce 73 | * @param[in] nonce2 The second nonce 74 | * @param[in] nonce3 The third nonce 75 | * @param[in] nonce4 The fourth nonce 76 | * @param[in] nonce5 The fifth nonce 77 | * 78 | * @return a status code 79 | */ 80 | static inline retcode_t mam_wots_gen_sk5(mam_wots_t *const wots, mam_prng_t const *const prng, trits_t const nonce1, 81 | trits_t const nonce2, trits_t const nonce3, trits_t const nonce4, 82 | trits_t const nonce5) { 83 | if (wots == NULL) { 84 | return RC_NULL_PARAM; 85 | } 86 | 87 | return mam_prng_gen5(prng, MAM_PRNG_DST_WOTS_KEY, nonce1, nonce2, nonce3, nonce4, nonce5, 88 | trits_from_rep(MAM_WOTS_PRIVATE_KEY_SIZE, wots->private_key)); 89 | } 90 | 91 | /** 92 | * @brief Generates a WOTS private key with a nonce 93 | * 94 | * @param[out] wots The WOTS private key 95 | * @param[in] prng A PRNG 96 | * @param[in] nonce The nonce 97 | * 98 | * @return a status code 99 | */ 100 | static inline retcode_t mam_wots_gen_sk(mam_wots_t *const wots, mam_prng_t const *const prng, trits_t const nonce) { 101 | return mam_wots_gen_sk5(wots, prng, nonce, trits_null(), trits_null(), trits_null(), trits_null()); 102 | } 103 | 104 | /** 105 | * @brief Generates a WOTS public key associated with a WOTS private key 106 | * 107 | * The private key must have already been generated 108 | * 109 | * @param[in] wots The WOTS private key 110 | * @param[out] public_key The WOTS public key 111 | * 112 | * @return a status code 113 | */ 114 | retcode_t mam_wots_gen_pk(mam_wots_t const *const wots, trits_t public_key); 115 | 116 | /** 117 | * @brief Generates a WOTS signature associated with a WOTS private key 118 | * 119 | * @param[in] wots The WOTS private key 120 | * @param[in] hash A hash to be signed 121 | * @param[out] signature The WOTS signature 122 | * 123 | * @return a status code 124 | */ 125 | retcode_t mam_wots_sign(mam_wots_t const *const wots, trits_t const hash, trits_t signature); 126 | 127 | /** 128 | * @brief Recovers a WOTS public key from a WOTS signature 129 | * 130 | * @param[in] hash A signed hash 131 | * @param[in] signature The WOTS signature 132 | * @param[out] public_key The WOTS public key 133 | * 134 | * @return a status code 135 | */ 136 | retcode_t mam_wots_recover(trits_t const hash, trits_t const signature, trits_t public_key); 137 | 138 | #ifdef __cplusplus 139 | } 140 | #endif 141 | 142 | #endif // __MAM_WOTS_WOTS_H__ 143 | 144 | /** @} */ 145 | -------------------------------------------------------------------------------- /tools/buildifier: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | buildifier -mode=fix $(find $(git rev-parse --show-toplevel) | grep -E "WORKSPACE|BUILD(\.(bazel|bzl))?\$") 4 | -------------------------------------------------------------------------------- /tools/ci_buildifier_check: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | buildifier -mode=check $(find . -type f | grep -E "WORKSPACE|BUILD(\.(bazel|bzl))?\$") 4 | -------------------------------------------------------------------------------- /tools/ci_format_check: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | root=$(git rev-parse --show-toplevel) 4 | status=0 5 | for file in $(find "${@}" -type f | grep -E "\.(c|cc|cpp|h|hh|hpp)\$") 6 | do 7 | filepath="$root/$file" 8 | output=$(diff <(cat $filepath) <(clang-format -style=file -fallback-style=none $filepath)) 9 | if [ $? -ne 0 ] 10 | then 11 | echo -e "\nFile \e[31m\""$file"\"\e[39m is not compliant with the coding style" 12 | echo "$output" 13 | status=1 14 | fi 15 | done 16 | exit $status 17 | -------------------------------------------------------------------------------- /tools/formatter: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | for file in $(find $(git rev-parse --show-toplevel) | grep -E "\.(c|cc|cpp|h|hh|hpp|m|mm)\$") 4 | do 5 | clang-format -style=file -fallback-style=none -i $file 6 | done 7 | -------------------------------------------------------------------------------- /tools/hooks/autohook.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Autohook 4 | # A very, very small Git hook manager with focus on automation 5 | # Author: Nik Kantar 6 | # Version: 2.1.1 7 | # Website: https://github.com/nkantar/Autohook 8 | # License: MIT - 9 | 10 | # MIT License 11 | # 12 | # Copyright (c) 2017 Nikola Kantar 13 | # 14 | # Permission is hereby granted, free of charge, to any person obtaining a copy 15 | # of this software and associated documentation files (the "Software"), to deal 16 | # in the Software without restriction, including without limitation the rights 17 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 18 | # copies of the Software, and to permit persons to whom the Software is 19 | # furnished to do so, subject to the following conditions: 20 | # 21 | # The above copyright notice and this permission notice shall be included in all 22 | # copies or substantial portions of the Software. 23 | # 24 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 27 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 29 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 | # SOFTWARE. 31 | 32 | 33 | echo() { 34 | builtin echo "[Autohook] $@"; 35 | } 36 | 37 | 38 | install() { 39 | hook_types=( 40 | "applypatch-msg" 41 | "commit-msg" 42 | "post-applypatch" 43 | "post-checkout" 44 | "post-commit" 45 | "post-merge" 46 | "post-receive" 47 | "post-rewrite" 48 | "post-update" 49 | "pre-applypatch" 50 | "pre-auto-gc" 51 | "pre-commit" 52 | "pre-push" 53 | "pre-rebase" 54 | "pre-receive" 55 | "prepare-commit-msg" 56 | "update" 57 | ) 58 | 59 | repo_root=$(git rev-parse --show-toplevel) 60 | hooks_dir="$repo_root/.git/hooks" 61 | autohook_filename="$repo_root/tools/hooks/autohook.sh" 62 | autohook_path=$(realpath $autohook_filename) 63 | for hook_type in "${hook_types[@]}" 64 | do 65 | hook_symlink="$hooks_dir/$hook_type" 66 | ln -sf $autohook_path $hook_symlink 67 | done 68 | } 69 | 70 | 71 | main() { 72 | calling_file=$(basename $0) 73 | 74 | if [[ $calling_file == "autohook.sh" ]] 75 | then 76 | command=$1 77 | if [[ $command == "install" ]] 78 | then 79 | install 80 | fi 81 | else 82 | repo_root=$(git rev-parse --show-toplevel) 83 | hook_type=$calling_file 84 | symlinks_dir="$repo_root/tools/hooks/$hook_type" 85 | files=("$symlinks_dir"/*) 86 | number_of_symlinks="${#files[@]}" 87 | if [[ $number_of_symlinks == 1 ]] 88 | then 89 | if [[ "$(basename ${files[0]})" == "*" ]] 90 | then 91 | number_of_symlinks=0 92 | fi 93 | fi 94 | echo "Looking for $hook_type scripts to run...found $number_of_symlinks!" 95 | if [[ $number_of_symlinks -gt 0 ]] 96 | then 97 | hook_exit_code=0 98 | for file in "${files[@]}" 99 | do 100 | scriptname=$(basename $file) 101 | echo "BEGIN $scriptname" 102 | eval $file &> /dev/null 103 | script_exit_code=$? 104 | if [[ $script_exit_code != 0 ]] 105 | then 106 | hook_exit_code=$script_exit_code 107 | fi 108 | echo "FINISH $scriptname" 109 | done 110 | if [[ $hook_exit_code != 0 ]] 111 | then 112 | echo "A $hook_type script yielded negative exit code $hook_exit_code" 113 | exit $hook_exit_code 114 | fi 115 | fi 116 | fi 117 | } 118 | 119 | 120 | main "$@" 121 | -------------------------------------------------------------------------------- /tools/hooks/pre-commit/01-buildifier-check: -------------------------------------------------------------------------------- 1 | ../scripts/buildifier_check -------------------------------------------------------------------------------- /tools/hooks/pre-commit/02-format-check: -------------------------------------------------------------------------------- 1 | ../scripts/format_check -------------------------------------------------------------------------------- /tools/hooks/scripts/buildifier_check: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | buildifier -mode=check $(git ls-files $(git rev-parse --show-toplevel) | grep -E "WORKSPACE|BUILD(\.(bazel|bzl))?\$") 4 | -------------------------------------------------------------------------------- /tools/hooks/scripts/format_check: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | root=$(git rev-parse --show-toplevel) 4 | status=0 5 | for file in $(git diff --staged --name-only | grep -E "\.(c|cc|cpp|h|hh|hpp)\$") 6 | do 7 | filepath="$root/$file" 8 | output=$(diff <(cat $filepath) <(clang-format -style=file -fallback-style=none $filepath)) 9 | if [ $? -ne 0 ] 10 | then 11 | echo -e "\nFile \""$file"\" is not compliant with the coding style" 12 | echo "$output" 13 | status=1 14 | fi 15 | done 16 | exit $status 17 | --------------------------------------------------------------------------------