diff --git a/c/auth.c b/c/auth.c index 7cd076f..d8c17e8 100644 --- a/c/auth.c +++ b/c/auth.c @@ -51,16 +51,6 @@ #define SOLANA_BLOCKHASH_SIZE 32 #define SOLANA_MESSAGE_HEADER_SIZE 3 -#define TONCOIN_PUBKEY_SIZE 32 -#define TONCOIN_SIGNATURE_SIZE 64 -#define TONCOIN_WRAPPED_SIGNATURE_SIZE 512 -#define TONCOIN_UNWRAPPED_SIGNATURE_SIZE 510 -#define TONCOIN_BLOCKHASH_SIZE 32 -#define TONCOIN_MESSAGE_PREFIX_SIZE 18 -#define TONCOIN_MAX_PREIMAGE_SIZE 512 -#define TONCOIN_MESSAGE_PREFIX2_SIZE 11 -#define TONCOIN_PREIMAGE2_SIZE (2 + TONCOIN_MESSAGE_PREFIX2_SIZE + 32) - #define MESSAGE_HEX_LEN 64 #define ED25519_SIGNATURE_SIZE 64 #define ED25519_PUBKEY_SIZE 32 @@ -622,85 +612,6 @@ int validate_signature_solana(uint8_t *prefilled_data, uint8_t algorithm_id, return 0; } -// Ton uses ed25519 to sign messages. The message to be signed is -// message = utf8_encode("ton-proof-item-v2/") ++ -// Address ++ -// AppDomain ++ -// Timestamp ++ -// Payload -// signature = Ed25519Sign(privkey, sha256(0xffff ++ utf8_encode("ton-connect") -// ++ sha256(message))) where Prefix = 18 bytes "ton-proof-item-v2/" without -// trailing null Address = Big endian work chain (uint32) + address (32 bytes) -// AppDomain = Little endian domain length (uint32) + domain (string without -// trailling null) Timestamp = Epoch seconds Little endian uint64 Payload = -// Arbitrary bytes, we use block hash here See ton official document on -// ton-proof https://docs.ton.org/develop/dapps/ton-connect/sign -int get_toncoin_message(const uint8_t *signed_msg, size_t signed_msg_len, - const uint8_t *blockhash, uint8_t output[32]) { - int err = 0; - uint8_t preimage1[TONCOIN_MAX_PREIMAGE_SIZE]; - uint8_t preimage2[TONCOIN_PREIMAGE2_SIZE]; - - int preimage1_size = - signed_msg_len + TONCOIN_MESSAGE_PREFIX_SIZE + TONCOIN_BLOCKHASH_SIZE; - CHECK2(preimage1_size <= TONCOIN_MAX_PREIMAGE_SIZE, ERROR_INVALID_ARG); - - const mbedtls_md_info_t *md_info = - mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); - - memcpy(preimage1, "ton-proof-item-v2/", TONCOIN_MESSAGE_PREFIX_SIZE); - memcpy(preimage1 + TONCOIN_MESSAGE_PREFIX_SIZE, signed_msg, signed_msg_len); - memcpy(preimage1 + TONCOIN_MESSAGE_PREFIX_SIZE + signed_msg_len, blockhash, - TONCOIN_BLOCKHASH_SIZE); - preimage2[0] = 0xff; - preimage2[1] = 0xff; - memcpy(preimage2 + 2, "ton-connect", TONCOIN_MESSAGE_PREFIX2_SIZE); - - CHECK(md_string(md_info, preimage1, preimage1_size, - preimage2 + 2 + TONCOIN_MESSAGE_PREFIX2_SIZE)); - CHECK(md_string(md_info, preimage2, TONCOIN_PREIMAGE2_SIZE, output)); -exit: - return err; -} - -int validate_signature_toncoin(uint8_t *prefilled_data, uint8_t algorithm_id, - const uint8_t *sig, size_t sig_len, - const uint8_t *msg, size_t msg_len, - uint8_t *out_pubkey_hash, - size_t pubkey_hash_len) { - int err = 0; - - CHECK2(sig_len == TONCOIN_WRAPPED_SIGNATURE_SIZE, ERROR_INVALID_ARG); - CHECK2(msg_len == TONCOIN_BLOCKHASH_SIZE, ERROR_INVALID_ARG); - sig_len = (size_t)sig[0] | ((size_t)sig[1] << 8); - CHECK2(sig_len <= TONCOIN_UNWRAPPED_SIGNATURE_SIZE, ERROR_INVALID_ARG); - const uint8_t *signature_ptr = sig + 2; - const uint8_t *pub_key_ptr = signature_ptr + TONCOIN_SIGNATURE_SIZE; - const uint8_t *signed_msg_ptr = - signature_ptr + TONCOIN_SIGNATURE_SIZE + TONCOIN_PUBKEY_SIZE; - size_t signed_msg_len = - sig_len - TONCOIN_SIGNATURE_SIZE - TONCOIN_PUBKEY_SIZE; - - uint8_t message[32]; - CHECK(get_toncoin_message(signed_msg_ptr, signed_msg_len, msg, message)); - - int suc = - ed25519_verify(signature_ptr, message, sizeof(message), pub_key_ptr); - CHECK2(suc == 1, ERROR_WRONG_STATE); - - blake2b_state ctx; - uint8_t pubkey_hash[BLAKE2B_BLOCK_SIZE] = {0}; - blake2b_init(&ctx, BLAKE2B_BLOCK_SIZE); - blake2b_update(&ctx, pub_key_ptr, TONCOIN_PUBKEY_SIZE); - blake2b_final(&ctx, pubkey_hash, sizeof(pubkey_hash)); - - uint8_t test_pubkey_hash[AUTH160_SIZE] = {0}; - // memcpy(output, pubkey_hash, AUTH160_SIZE); - memcpy(out_pubkey_hash, test_pubkey_hash, AUTH160_SIZE); -exit: - return err; -} - int convert_copy(const uint8_t *msg, size_t msg_len, uint8_t *new_msg, size_t new_msg_len) { if (msg_len != new_msg_len || msg_len != BLAKE2B_BLOCK_SIZE) @@ -1092,9 +1003,6 @@ __attribute__((visibility("default"))) int ckb_auth_validate( err = verify(&validator, validate_signature_ripple, convert_ripple_message); CHECK(err); - } else if (algorithm_id == AuthAlgorithmIdToncoin) { - err = verify(&validator, validate_signature_toncoin, convert_copy); - CHECK(err); } else if (algorithm_id == AuthAlgorithmIdOwnerLock) { CHECK2(is_lock_script_hash_present(pubkey_hash), ERROR_MISMATCHED); err = 0; diff --git a/c/ckb_auth.h b/c/ckb_auth.h index ceb2987..29533bc 100644 --- a/c/ckb_auth.h +++ b/c/ckb_auth.h @@ -85,7 +85,7 @@ enum AuthAlgorithmIdType { AuthAlgorithmIdSolana = 13, AuthAlgorithmIdRipple = 14, AuthAlgorithmIdSecp256R1 = 15, - AuthAlgorithmIdToncoin = 16, + // AuthAlgorithmIdToncoin = 16, AuthAlgorithmIdSecp256R1Raw = 17, AuthAlgorithmIdOwnerLock = 0xFC, }; diff --git a/ckb-auth-rs/src/lib.rs b/ckb-auth-rs/src/lib.rs index cba96b7..0405f15 100644 --- a/ckb-auth-rs/src/lib.rs +++ b/ckb-auth-rs/src/lib.rs @@ -44,7 +44,7 @@ pub enum AuthAlgorithmIdType { Solana = 13, Ripple = 14, Secp256r1 = 15, - Toncoin = 16, + // Toncoin = 16, Secp256r1Raw = 17, OwnerLock = 0xFC, } diff --git a/docs/auth.md b/docs/auth.md index 9deb4a9..38c2b9a 100644 --- a/docs/auth.md +++ b/docs/auth.md @@ -146,15 +146,6 @@ Key parameters: - pubkey: 32 compressed pubkey. - pubkey hash: sha256 and ripemd160 of pubkey, refer to [ckb-auth-cli ripple parse](../tools/ckb-auth-cli/src/ripple.rs). -#### Toncoin (algorithm_id=16) -The witness of a valid toncoin transaction should be a sequence of the following data. -The whole length of the witness must be exactly 512. If there are any space left, pad it with zero. - -- size of the following data combined (little-endian `uint16_t`) -- signature -- public key -- the message without prefix and payload - ### Low Level APIs We define some low level APIs to auth libraries, which can be also used for other purposes. diff --git a/docs/toncoin.md b/docs/toncoin.md deleted file mode 100644 index a150ac3..0000000 --- a/docs/toncoin.md +++ /dev/null @@ -1,99 +0,0 @@ -# [TONCOIN](../README.md) - -# Installing toncoin and setup a wallet - -First [get a wallet](https://ton.org/en/wallets?locale=en&pagination[limit]=-1) -and set up a wallet account. - -# Creating a `ton_proof` with the wallet - -TODO: any easier way to create `ton_proof` for arbitrary message? - -In order to sign CKB transactions with toncoin, we need to create -[`ton_proof`](https://docs.ton.org/develop/dapps/ton-connect/protocol/requests-responses#address-proof-signature-ton_proof) -with the wallet extension/app, which is an ed25519 signature to -an message related to CKB transaction. - -We need to follow the instructions from [Signing and Verification | The Open Network](https://docs.ton.org/develop/dapps/ton-connect/sign), -create an javascript application to talk to the browser extension and then ask the extension to create a valid ton_proof for the message `hex(sighash_all)` (i.e. the hex string of the result of [generate_sighash_all](https://github.com/nervosnetwork/ckb-auth/pull/22)). - -Under the hood, ton wallet extension would create a ed25519 signature as follows - -``` -signature = Ed25519Sign(privkey, sha256(0xffff ++ utf8_encode("ton-connect") ++ sha256(message))) -message = utf8_encode("ton-proof-item-v2/") ++ - Address ++ - AppDomain ++ - Timestamp ++ - Payload -``` - -where - -``` -Prefix = 18 bytes "ton-proof-item-v2/" string without trailing null -Address = Big endian work chain (uint32) + address (32 bytes) -AppDomain = Little endian domain length (uint32) + domain (string without trailling null) -Timestamp = Epoch seconds Little endian uint64 -Payload = Arbitrary bytes, we use the result of applying sighash_all to the transaction here -``` - -Below is a sample of `ton_proof` created by [Tonkeeper](https://tonkeeper.com/) to -[Getgems](https://getgems.io/). - -``` -{ - "operationName": "loginTonConnect", - "variables": { - "payload": { - "address": "0:a0b96c234f6dede6d56df40ca81315bb73c30d1a9d9f8fbc14d440c73ef6d510", - "authApplication": "prd=injected plf=windows app=Tonkeeper v=3.3.12 mp=2 f=SendTransaction,[object Object]", - "chain": "-239", - "domainLengthBytes": 10, - "domainValue": "getgems.io", - "payload": "gems", - "signature": "eN9vr+Yv6vm5iBuC/daBC18PqwhGUAedtODHuaSh1VJBOKwrQ2ICOk/31YjDTUYxGaHZ7eT+L4dJN1oJGuK5AQ==", - "timestamp": 1698873010, - "walletStateInit": "te6cckECFgEAAwQAAgE0AgEAUQAAAAApqaMXfVPCXYWmAMWvtyplExvJyD5PxMuxMpRSUFk34gJrsFxAART/APSkE/S88sgLAwIBIAkEBPjygwjXGCDTH9Mf0x8C+CO78mTtRNDTH9Mf0//0BNFRQ7ryoVFRuvKiBfkBVBBk+RDyo/gAJKTIyx9SQMsfUjDL/1IQ9ADJ7VT4DwHTByHAAJ9sUZMg10qW0wfUAvsA6DDgIcAB4wAhwALjAAHAA5Ew4w0DpMjLHxLLH8v/CAcGBQAK9ADJ7VQAbIEBCNcY+gDTPzBSJIEBCPRZ8qeCEGRzdHJwdIAYyMsFywJQBc8WUAP6AhPLassfEss/yXP7AABwgQEI1xj6ANM/yFQgR4EBCPRR8qeCEG5vdGVwdIAYyMsFywJQBs8WUAT6AhTLahLLH8s/yXP7AAIAbtIH+gDU1CL5AAXIygcVy//J0Hd0gBjIywXLAiLPFlAF+gIUy2sSzMzJc/sAyEAUgQEI9FHypwICAUgTCgIBIAwLAFm9JCtvaiaECAoGuQ+gIYRw1AgIR6STfSmRDOaQPp/5g3gSgBt4EBSJhxWfMYQCASAODQARuMl+1E0NcLH4AgFYEg8CASAREAAZrx32omhAEGuQ64WPwAAZrc52omhAIGuQ64X/wAA9sp37UTQgQFA1yH0BDACyMoHy//J0AGBAQj0Cm+hMYALm0AHQ0wMhcbCSXwTgItdJwSCSXwTgAtMfIYIQcGx1Z70ighBkc3RyvbCSXwXgA/pAMCD6RAHIygfL/8nQ7UTQgQFA1yH0BDBcgQEI9ApvoTGzkl8H4AXTP8glghBwbHVnupI4MOMNA4IQZHN0crqSXwbjDRUUAIpQBIEBCPRZMO1E0IEBQNcgyAHPFvQAye1UAXKwjiOCEGRzdHKDHrFwgBhQBcsFUAPPFiP6AhPLassfyz/JgED7AJJfA+IAeAH6APQEMPgnbyIwUAqhIb7y4FCCEHBsdWeDHrFwgBhQBMsFJs8WWPoCGfQAy2kXyx9SYMs/IMmAQPsABpq/MVw=", - "publicKey": "7d53c25d85a600c5afb72a65131bc9c83e4fc4cbb1329452505937e2026bb05c" - } - }, - "extensions": { - "persistedQuery": { - "version": 1, - "sha256Hash": "b3dee5aa59be0610e5fe26054d974fd7d561f5db9987769b21d302635e48b4ab" - } - } -} -``` - -In this example, the message to be signed is -`sha256(0xffff ++ utf8_encode("ton-connect") ++ sha256(message)))` - -where `message` is the concatenation of - -``` -746f6e2d70726f6f662d6974656d2d76322f (prefix "ton-proof-item-v2/") -00000000 (work chain) -a0b96c234f6dede6d56df40ca81315bb73c30d1a9d9f8fbc14d440c73ef6d510 (address) -0a000000 (domain length) -67657467656d732e696f (domain "getgems.io") -b2be426500000000 (timestamp) -payload 67656d73 (payload "gems") -``` - -A valid CKB transaction is one valid `ton_proof` created with ckb sighash_all result as payload. - -# Required information for ckb-auth to verify the validity of `ton_proof` - -Ckb-auth requires the signature, public key and `message` structure above without payload -(payload is assumed to be sighash_all result in valid CKB transaction) -to verify the validity of the signature. - -Given the above `ton_proof` a valid transaction witness can be constructed as follows. - -Since the size of the witness is not static (as the message is dynamically-sized) and -its length is relevant in computing transaction hash. We pad the whole witness to a memory region of size -512. The first part of these memory region is a little-endian `uint16_t` integer represents the length of -the effective witness. From there follows the signature and public key, finally the message without prefix and payload, -i.e. Address ++ AppDomain ++ Timestamp above. diff --git a/tests/auth-c-tests/src/lib.rs b/tests/auth-c-tests/src/lib.rs index 154ad0a..e588516 100644 --- a/tests/auth-c-tests/src/lib.rs +++ b/tests/auth-c-tests/src/lib.rs @@ -867,7 +867,6 @@ pub fn auth_builder(t: AuthAlgorithmIdType, official: bool) -> result::Result { return Ok(Secp256r1Auth::new()); } - AuthAlgorithmIdType::Toncoin => todo!("Toncoin tests currectly unimplemented"), AuthAlgorithmIdType::Secp256r1Raw => { return Ok(Secp256r1RawAuth::new()); }