Skip to content

Commit

Permalink
Merge pull request #206 from Zondax/update-10100
Browse files Browse the repository at this point in the history
  • Loading branch information
carlosala committed Jan 12, 2024
2 parents cede2db + 56e448c commit 8483413
Show file tree
Hide file tree
Showing 111 changed files with 84,838 additions and 82,563 deletions.
2 changes: 0 additions & 2 deletions .github/workflows/guidelines_enforcer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,3 @@ jobs:
guidelines_enforcer:
name: Call Ledger guidelines_enforcer
uses: LedgerHQ/ledger-app-workflows/.github/workflows/reusable_guidelines_enforcer.yml@v1
with:
relative_app_directory: app
109 changes: 61 additions & 48 deletions README.md

Large diffs are not rendered by default.

4 changes: 1 addition & 3 deletions app/Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#*******************************************************************************
# Ledger App
# (c) 2019 - 2023 Zondax AG
# (c) 2019 - 2024 Zondax AG
# (c) 2017 Ledger
#
# Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -77,8 +77,6 @@ endif

APP_LOAD_PARAMS = --curve ed25519 $(COMMON_LOAD_PARAMS) --path $(APPPATH)

NANOS_STACK_SIZE := 3216

include $(CURDIR)/../deps/ledger-zxlib/makefiles/Makefile.devices

$(info TARGET_NAME = [$(TARGET_NAME)])
Expand Down
4 changes: 2 additions & 2 deletions app/Makefile.version
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# This is the `transaction_version` field of `Runtime`
APPVERSION_M=24
APPVERSION_M=25
# This is the `spec_version` field of `Runtime`
APPVERSION_N=10000
APPVERSION_N=10100
# This is the patch version of this release
APPVERSION_P=0
2 changes: 1 addition & 1 deletion app/src/common/parser_common.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* (c) 2019 - 2023 Zondax AG
* (c) 2019 - 2024 Zondax AG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down
26 changes: 13 additions & 13 deletions app/src/crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,13 @@ static zxerr_t crypto_extractPublicKey(key_kind_e addressKind, uint8_t *pubKey,
privateKeyData,
NULL,
NULL,
0))
0));

switch (addressKind) {
case key_ed25519: {
CATCH_CXERROR(cx_ecfp_init_private_key_no_throw(CX_CURVE_Ed25519, privateKeyData, 32, &cx_privateKey))
CATCH_CXERROR(cx_ecfp_init_public_key_no_throw(CX_CURVE_Ed25519, NULL, 0, &cx_publicKey))
CATCH_CXERROR(cx_ecfp_generate_pair_no_throw(CX_CURVE_Ed25519, &cx_publicKey, &cx_privateKey, 1))
CATCH_CXERROR(cx_ecfp_init_private_key_no_throw(CX_CURVE_Ed25519, privateKeyData, 32, &cx_privateKey));
CATCH_CXERROR(cx_ecfp_init_public_key_no_throw(CX_CURVE_Ed25519, NULL, 0, &cx_publicKey));
CATCH_CXERROR(cx_ecfp_generate_pair_no_throw(CX_CURVE_Ed25519, &cx_publicKey, &cx_privateKey, 1));
for (unsigned int i = 0; i < PK_LEN_25519; i++) {
pubKey[i] = cx_publicKey.W[64 - i];
}
Expand All @@ -66,7 +66,7 @@ static zxerr_t crypto_extractPublicKey(key_kind_e addressKind, uint8_t *pubKey,
#ifdef SUPPORT_SR25519
case key_sr25519:
get_sr25519_sk(privateKeyData);
CATCH_CXERROR(crypto_scalarmult_ristretto255_base_sdk(pubKey, privateKeyData))
CATCH_CXERROR(crypto_scalarmult_ristretto255_base_sdk(pubKey, privateKeyData));
error = zxerr_ok;
break;
#endif
Expand Down Expand Up @@ -100,8 +100,8 @@ zxerr_t crypto_sign_ed25519(uint8_t *signature, uint16_t signatureMaxlen, const
if (messageLen > MAX_SIGN_SIZE) {
// Hash it
cx_blake2b_t ctx;
CATCH_CXERROR(cx_blake2b_init_no_throw(&ctx, 256))
CATCH_CXERROR(cx_hash_no_throw(&ctx.header, CX_LAST, message, messageLen, messageDigest, BLAKE2B_DIGEST_SIZE))
CATCH_CXERROR(cx_blake2b_init_no_throw(&ctx, 256));
CATCH_CXERROR(cx_hash_no_throw(&ctx.header, CX_LAST, message, messageLen, messageDigest, BLAKE2B_DIGEST_SIZE));
toSign = messageDigest;
messageLen = BLAKE2B_DIGEST_SIZE;
}
Expand All @@ -114,9 +114,9 @@ zxerr_t crypto_sign_ed25519(uint8_t *signature, uint16_t signatureMaxlen, const
privateKeyData,
NULL,
NULL,
0))
0));

CATCH_CXERROR(cx_ecfp_init_private_key_no_throw(CX_CURVE_Ed25519, privateKeyData, SCALAR_LEN_ED25519, &cx_privateKey))
CATCH_CXERROR(cx_ecfp_init_private_key_no_throw(CX_CURVE_Ed25519, privateKeyData, SCALAR_LEN_ED25519, &cx_privateKey));

// Sign
*signature = PREFIX_SIGNATURE_TYPE_ED25519;
Expand All @@ -125,7 +125,7 @@ zxerr_t crypto_sign_ed25519(uint8_t *signature, uint16_t signatureMaxlen, const
toSign,
messageLen,
signature + 1,
signatureMaxlen - 1))
signatureMaxlen - 1));
error = zxerr_ok;

catch_cx_error:
Expand Down Expand Up @@ -172,13 +172,13 @@ static zxerr_t crypto_sign_sr25519_helper(const uint8_t *data, size_t len) {
privateKeyData,
NULL,
NULL,
0))
0));

get_sr25519_sk(privateKeyData);
CATCH_CXERROR(crypto_scalarmult_ristretto255_base_sdk(pubkey, privateKeyData))
CATCH_CXERROR(crypto_scalarmult_ristretto255_base_sdk(pubkey, privateKeyData));
*sr25519_signature = PREFIX_SIGNATURE_TYPE_SR25519;
sign_sr25519_phase1(privateKeyData, pubkey, NULL, 0, data, len, sr25519_signature + 1);
CATCH_CXERROR(crypto_scalarmult_ristretto255_base_sdk(sr25519_signature + 1, sr25519_signature + 1 + PK_LEN_25519))
CATCH_CXERROR(crypto_scalarmult_ristretto255_base_sdk(sr25519_signature + 1, sr25519_signature + 1 + PK_LEN_25519));
error = zxerr_ok;

catch_cx_error:
Expand Down
6 changes: 3 additions & 3 deletions app/src/crypto_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ cx_err_t ss58hash(const unsigned char *in, unsigned int inLen,
unsigned char *out, unsigned int outLen) {

cx_blake2b_t ctx;
CHECK_CXERROR(cx_blake2b_init_no_throw(&ctx, 512))
CHECK_CXERROR(cx_hash_no_throw(&ctx.header, 0, SS58_BLAKE_PREFIX, SS58_BLAKE_PREFIX_LEN, NULL, 0))
CHECK_CXERROR(cx_hash_no_throw(&ctx.header, CX_LAST, in, inLen, out, outLen))
CHECK_CXERROR(cx_blake2b_init_no_throw(&ctx, 512));
CHECK_CXERROR(cx_hash_no_throw(&ctx.header, 0, SS58_BLAKE_PREFIX, SS58_BLAKE_PREFIX_LEN, NULL, 0));
CHECK_CXERROR(cx_hash_no_throw(&ctx.header, CX_LAST, in, inLen, out, outLen));

return CX_OK;
}
Expand Down
2 changes: 1 addition & 1 deletion app/src/parser_impl.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* (c) 2019 - 2023 Zondax AG
* (c) 2019 - 2024 Zondax AG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down
2 changes: 1 addition & 1 deletion app/src/parser_impl_common.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* (c) 2019 - 2023 Zondax AG
* (c) 2019 - 2024 Zondax AG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down
84 changes: 42 additions & 42 deletions app/src/ristretto.c
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ static cx_err_t fe25519_cneg_sdk(fe25519_sdk h, const fe25519_sdk f, unsigned in
{
fe25519_sdk negf;

CHECK_CXERROR(fe25519_neg_sdk(negf, f))
CHECK_CXERROR(fe25519_neg_sdk(negf, f));
fe25519_copy_sdk(h, f);
fe25519_cmov_sdk(h, negf, b);

Expand Down Expand Up @@ -153,28 +153,28 @@ static cx_err_t ristretto255_sqrt_ratio_m1_sdk(fe25519_sdk x, const fe25519_sdk
fe25519_sdk x_sqrtm1;
int has_p_root, has_f_root;

CHECK_CXERROR(fe25519_sq_sdk(v3, v))
CHECK_CXERROR(fe25519_mul_sdk(v3, v3, v)) /* v3 = v^3 */
CHECK_CXERROR(fe25519_sq_sdk(x, v3))
CHECK_CXERROR(fe25519_mul_sdk(x, x, u))
CHECK_CXERROR(fe25519_mul_sdk(x, x, v)) /* x = uv^7 */

CHECK_CXERROR(fe25519_pow22523_sdk(x, x)) /* x = (uv^7)^((q-5)/8) */
CHECK_CXERROR(fe25519_mul_sdk(x, x, v3))
CHECK_CXERROR(fe25519_mul_sdk(x, x, u)) /* x = uv^3(uv^7)^((q-5)/8) */

CHECK_CXERROR(fe25519_sq_sdk(vxx, x))
CHECK_CXERROR(fe25519_mul_sdk(vxx, vxx, v)) /* vx^2 */
CHECK_CXERROR(fe25519_sub_sdk(m_root_check, vxx, u)) /* vx^2-u */
CHECK_CXERROR(fe25519_add_sdk(p_root_check, vxx, u)) /* vx^2+u */
CHECK_CXERROR(fe25519_mul_sdk(f_root_check, u, fe25519_sqrtm1_sdk)) /* u*sqrt(-1) */
CHECK_CXERROR(fe25519_add_sdk(f_root_check, vxx, f_root_check)) /* vx^2+u*sqrt(-1) */
CHECK_CXERROR(fe25519_sq_sdk(v3, v));
CHECK_CXERROR(fe25519_mul_sdk(v3, v3, v)); /* v3 = v^3 */
CHECK_CXERROR(fe25519_sq_sdk(x, v3));
CHECK_CXERROR(fe25519_mul_sdk(x, x, u));
CHECK_CXERROR(fe25519_mul_sdk(x, x, v)); /* x = uv^7 */

CHECK_CXERROR(fe25519_pow22523_sdk(x, x)); /* x = (uv^7)^((q-5)/8) */
CHECK_CXERROR(fe25519_mul_sdk(x, x, v3));
CHECK_CXERROR(fe25519_mul_sdk(x, x, u)); /* x = uv^3(uv^7)^((q-5)/8) */

CHECK_CXERROR(fe25519_sq_sdk(vxx, x));
CHECK_CXERROR(fe25519_mul_sdk(vxx, vxx, v)); /* vx^2 */
CHECK_CXERROR(fe25519_sub_sdk(m_root_check, vxx, u)); /* vx^2-u */
CHECK_CXERROR(fe25519_add_sdk(p_root_check, vxx, u)); /* vx^2+u */
CHECK_CXERROR(fe25519_mul_sdk(f_root_check, u, fe25519_sqrtm1_sdk)); /* u*sqrt(-1) */
CHECK_CXERROR(fe25519_add_sdk(f_root_check, vxx, f_root_check)); /* vx^2+u*sqrt(-1) */
has_p_root = fe25519_iszero_sdk(p_root_check);
has_f_root = fe25519_iszero_sdk(f_root_check);
CHECK_CXERROR(fe25519_mul_sdk(x_sqrtm1,x, fe25519_sqrtm1_sdk))
CHECK_CXERROR(fe25519_mul_sdk(x_sqrtm1,x, fe25519_sqrtm1_sdk));

fe25519_cmov_sdk(x, x_sqrtm1, has_p_root | has_f_root);
CHECK_CXERROR(fe25519_abs_sdk(x, x))
CHECK_CXERROR(fe25519_abs_sdk(x, x));

return CX_OK;
}
Expand All @@ -197,28 +197,28 @@ static cx_err_t ristretto255_p3_tobytes_sdk(fe25519_sdk s, const ge25519_p3_sdk
fe25519_sdk zmy;
int rotate;

CHECK_CXERROR(fe25519_add_sdk(u1, h->Z, h->Y)) /* u1 = Z+Y */
CHECK_CXERROR(fe25519_sub_sdk(zmy, h->Z, h->Y)) /* zmy = Z-Y */
CHECK_CXERROR(fe25519_mul_sdk(u1, u1, zmy)) /* u1 = (Z+Y)*(Z-Y) */
CHECK_CXERROR(fe25519_mul_sdk(u2, h->X, h->Y)) /* u2 = X*Y */
CHECK_CXERROR(fe25519_add_sdk(u1, h->Z, h->Y)); /* u1 = Z+Y */
CHECK_CXERROR(fe25519_sub_sdk(zmy, h->Z, h->Y)); /* zmy = Z-Y */
CHECK_CXERROR(fe25519_mul_sdk(u1, u1, zmy)); /* u1 = (Z+Y)*(Z-Y) */
CHECK_CXERROR(fe25519_mul_sdk(u2, h->X, h->Y)); /* u2 = X*Y */

CHECK_CXERROR(fe25519_sq_sdk(u1_u2u2, u2)) /* u1_u2u2 = u2^2 */
CHECK_CXERROR(fe25519_mul_sdk(u1_u2u2, u1, u1_u2u2)) /* u1_u2u2 = u1*u2^2 */
CHECK_CXERROR(fe25519_sq_sdk(u1_u2u2, u2)); /* u1_u2u2 = u2^2 */
CHECK_CXERROR(fe25519_mul_sdk(u1_u2u2, u1, u1_u2u2)); /* u1_u2u2 = u1*u2^2 */

fe25519_1_sdk(one);
CHECK_CXERROR(ristretto255_sqrt_ratio_m1_sdk(inv_sqrt, one, u1_u2u2))
CHECK_CXERROR(ristretto255_sqrt_ratio_m1_sdk(inv_sqrt, one, u1_u2u2));

CHECK_CXERROR(fe25519_mul_sdk(den1, inv_sqrt, u1))
CHECK_CXERROR(fe25519_mul_sdk(den2, inv_sqrt, u2))
CHECK_CXERROR(fe25519_mul_sdk(z_inv, den1, den2))
CHECK_CXERROR(fe25519_mul_sdk(z_inv, z_inv, h->T))
CHECK_CXERROR(fe25519_mul_sdk(den1, inv_sqrt, u1));
CHECK_CXERROR(fe25519_mul_sdk(den2, inv_sqrt, u2));
CHECK_CXERROR(fe25519_mul_sdk(z_inv, den1, den2));
CHECK_CXERROR(fe25519_mul_sdk(z_inv, z_inv, h->T));

CHECK_CXERROR(fe25519_mul_sdk(ix, h->X, fe25519_sqrtm1_sdk))
CHECK_CXERROR(fe25519_mul_sdk(iy, h->Y, fe25519_sqrtm1_sdk))
CHECK_CXERROR(fe25519_mul_sdk(ix, h->X, fe25519_sqrtm1_sdk));
CHECK_CXERROR(fe25519_mul_sdk(iy, h->Y, fe25519_sqrtm1_sdk));

CHECK_CXERROR(fe25519_mul_sdk(eden, den1, ed25519_invsqrtamd_sdk))
CHECK_CXERROR(fe25519_mul_sdk(eden, den1, ed25519_invsqrtamd_sdk));

CHECK_CXERROR(fe25519_mul_sdk(t_z_inv, h->T, z_inv))
CHECK_CXERROR(fe25519_mul_sdk(t_z_inv, h->T, z_inv));
rotate = fe25519_isnegative_sdk(t_z_inv);

fe25519_copy_sdk(x_, h->X);
Expand All @@ -230,12 +230,12 @@ static cx_err_t ristretto255_p3_tobytes_sdk(fe25519_sdk s, const ge25519_p3_sdk
fe25519_cmov_sdk(y_, ix, rotate);
fe25519_cmov_sdk(den_inv, eden, rotate);

CHECK_CXERROR(fe25519_mul_sdk(x_z_inv, x_, z_inv))
CHECK_CXERROR(fe25519_cneg_sdk(y_, y_, fe25519_isnegative_sdk(x_z_inv)))
CHECK_CXERROR(fe25519_mul_sdk(x_z_inv, x_, z_inv));
CHECK_CXERROR(fe25519_cneg_sdk(y_, y_, fe25519_isnegative_sdk(x_z_inv)));

CHECK_CXERROR(fe25519_sub_sdk(s_, h->Z, y_))
CHECK_CXERROR(fe25519_mul_sdk(s_, den_inv, s_))
CHECK_CXERROR(fe25519_abs_sdk(s, s_))
CHECK_CXERROR(fe25519_sub_sdk(s_, h->Z, y_));
CHECK_CXERROR(fe25519_mul_sdk(s_, den_inv, s_));
CHECK_CXERROR(fe25519_abs_sdk(s, s_));

return CX_OK;
}
Expand All @@ -252,18 +252,18 @@ cx_err_t crypto_scalarmult_ristretto255_base_sdk(unsigned char *q,const unsigned

uint8_t Pxy[ED25519_SDKPOINT_BYTES];
memcpy(Pxy, ED25519_GEN, sizeof(Pxy));
CHECK_CXERROR(cx_ecfp_scalar_mult_no_throw(CX_CURVE_Ed25519, Pxy, t, ED25519_SCALAR_BYTES))
CHECK_CXERROR(cx_ecfp_scalar_mult_no_throw(CX_CURVE_Ed25519, Pxy, t, ED25519_SCALAR_BYTES));

ge25519_p3_sdk Q_sdk;
MEMZERO(&Q_sdk, sizeof(ge25519_p3_sdk));
memcpy(Q_sdk.X, &Pxy[1],ED25519_SCALAR_BYTES);
memcpy(Q_sdk.Y, &Pxy[1+ED25519_SCALAR_BYTES],ED25519_SCALAR_BYTES);
fe25519_1_sdk(Q_sdk.Z);
CHECK_CXERROR(fe25519_mul_sdk(Q_sdk.T, Q_sdk.X,Q_sdk.Y))
CHECK_CXERROR(fe25519_mul_sdk(Q_sdk.T, Q_sdk.X,Q_sdk.Y));

fe25519_sdk s;

CHECK_CXERROR(ristretto255_p3_tobytes_sdk(s, &Q_sdk))
CHECK_CXERROR(ristretto255_p3_tobytes_sdk(s, &Q_sdk));

if (fe25519_iszero_sdk(s)) {
return CX_INTERNAL_ERROR;
Expand Down
2 changes: 1 addition & 1 deletion app/src/substrate/substrate_coin.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* (c) 2019 - 2023 Zondax AG
* (c) 2019 - 2024 Zondax AG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down
34 changes: 17 additions & 17 deletions app/src/substrate/substrate_dispatch.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* (c) 2019 - 2023 Zondax AG
* (c) 2019 - 2024 Zondax AG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -26,8 +26,8 @@ parser_error_t _readMethod(
pd_Method_t* method)
{
switch (c->tx_obj->transactionVersion) {
case 24:
return _readMethod_V24(c, moduleIdx, callIdx, &method->V24);
case 25:
return _readMethod_V25(c, moduleIdx, callIdx, &method->V25);
default:
return parser_tx_version_not_supported;
}
Expand All @@ -36,8 +36,8 @@ parser_error_t _readMethod(
uint8_t _getMethod_NumItems(uint32_t transactionVersion, uint8_t moduleIdx, uint8_t callIdx)
{
switch (transactionVersion) {
case 24:
return _getMethod_NumItems_V24(moduleIdx, callIdx);
case 25:
return _getMethod_NumItems_V25(moduleIdx, callIdx);
default:
return 0;
}
Expand All @@ -46,8 +46,8 @@ uint8_t _getMethod_NumItems(uint32_t transactionVersion, uint8_t moduleIdx, uint
const char* _getMethod_ModuleName(uint32_t transactionVersion, uint8_t moduleIdx)
{
switch (transactionVersion) {
case 24:
return _getMethod_ModuleName_V24(moduleIdx);
case 25:
return _getMethod_ModuleName_V25(moduleIdx);
default:
return NULL;
}
Expand All @@ -56,8 +56,8 @@ const char* _getMethod_ModuleName(uint32_t transactionVersion, uint8_t moduleIdx
const char* _getMethod_Name(uint32_t transactionVersion, uint8_t moduleIdx, uint8_t callIdx)
{
switch (transactionVersion) {
case 24:
return _getMethod_Name_V24(moduleIdx, callIdx);
case 25:
return _getMethod_Name_V25(moduleIdx, callIdx);
default:
return NULL;
}
Expand All @@ -66,8 +66,8 @@ const char* _getMethod_Name(uint32_t transactionVersion, uint8_t moduleIdx, uint
const char* _getMethod_ItemName(uint32_t transactionVersion, uint8_t moduleIdx, uint8_t callIdx, uint8_t itemIdx)
{
switch (transactionVersion) {
case 24:
return _getMethod_ItemName_V24(moduleIdx, callIdx, itemIdx);
case 25:
return _getMethod_ItemName_V25(moduleIdx, callIdx, itemIdx);
default:
return NULL;
}
Expand All @@ -78,8 +78,8 @@ parser_error_t _getMethod_ItemValue(uint32_t transactionVersion, pd_Method_t* m,
uint8_t pageIdx, uint8_t* pageCount)
{
switch (transactionVersion) {
case 24:
return _getMethod_ItemValue_V24(&m->V24, moduleIdx, callIdx, itemIdx, outValue,
case 25:
return _getMethod_ItemValue_V25(&m->V25, moduleIdx, callIdx, itemIdx, outValue,
outValueLen, pageIdx, pageCount);
default:
return parser_tx_version_not_supported;
Expand All @@ -89,8 +89,8 @@ parser_error_t _getMethod_ItemValue(uint32_t transactionVersion, pd_Method_t* m,
bool _getMethod_ItemIsExpert(uint32_t transactionVersion, uint8_t moduleIdx, uint8_t callIdx, uint8_t itemIdx)
{
switch (transactionVersion) {
case 24:
return _getMethod_ItemIsExpert_V24(moduleIdx, callIdx, itemIdx);
case 25:
return _getMethod_ItemIsExpert_V25(moduleIdx, callIdx, itemIdx);
default:
return false;
}
Expand All @@ -99,8 +99,8 @@ bool _getMethod_ItemIsExpert(uint32_t transactionVersion, uint8_t moduleIdx, uin
bool _getMethod_IsNestingSupported(uint32_t transactionVersion, uint8_t moduleIdx, uint8_t callIdx)
{
switch (transactionVersion) {
case 24:
return _getMethod_IsNestingSupported_V24(moduleIdx, callIdx);
case 25:
return _getMethod_IsNestingSupported_V25(moduleIdx, callIdx);
default:
return false;
}
Expand Down

0 comments on commit 8483413

Please sign in to comment.