[wip] adding message signing functionality

Problem is this:

    Uncaught ReferenceError: require is not defined
        <anonymous> moz-extension://b4685fc7-232c-44d9-b653-f51b7c7ea868/dist/jex_include/local-vdk_aecrypt-0.1.0/dist/jex_include/local-blakejs-1.2.1/dist/index.js:1
    index.js:1:13

The issue is that blakejs is written for node and needs to be modified to work
in a browser.

Next task is doing that, but did a ton of work so taking a break
This commit is contained in:
2023-08-12 18:18:03 -06:00
parent 6d715612e4
commit 29defebc2e
19 changed files with 2253 additions and 3 deletions
+242
View File
@@ -0,0 +1,242 @@
/**
* Black boxes away all the AE-specific cryptography routines that call other
* libs
*
* Refs:
* 1. https://github.com/aeternity/aepp-sdk-js/blob/5df22dd297abebc0607710793a7234e6761570d4/src/utils/crypto.ts#L141-L
* 2. https://github.com/aeternity/aepp-sdk-js/blob/5df22dd297abebc0607710793a7234e6761570d4/src/utils/crypto.ts#L160-L
* 3. https://github.com/aeternity/Vanillae/blob/f054744bbceb957afa8fbcf31d93055dd277396b/sidekick/src/sidekick.ts#L926-L1015
*
* @module
*/
import * as blakejs from './jex_include/local-blakejs-1.2.1/dist/index.js';
import * as vdk_binary from './jex_include/local-vdk_binary-0.1.0/dist/vdk_binary.js';
export {
hash_and_salt_msg,
salt_msg,
btc_varuint_encode
}
/**
* Quoth https://github.com/aeternity/Vanillae/blob/f054744bbceb957afa8fbcf31d93055dd277396b/sidekick/src/sidekick.ts#L926-L1015
*
* > In order to exclude the possibility of someone using this functionality to
* > trick the user into signing a transaction, the wallet salts and hashes the
* > message, and *then* signs the salted/hashed message.
* >
* > Therefore, naively attempting to verify the signature will not work. You
* > must apply the same preprocessing steps as the wallet, **THEN** check the
* > signature against the salted/hashed message.
* >
* > ```erlang
* > -spec hashed_salted_msg(Message) -> HashedSaltedMessage
* > when Message :: binary(),
* > HashedSaltedMessage :: binary().
* > % @doc Salt the message then hash with blake2b. See:
* > % 1. https://github.com/aeternity/aepp-sdk-js/blob/370f1e30064ad0239ba59931908d9aba0a2e86b6/src/utils/crypto.ts#L83-L85
* > % 2. https://github.com/aeternity/eblake2/blob/60a079f00d72d1bfcc25de8e6996d28f912db3fd/src/eblake2.erl#L23-L25
* >
* > hashed_salted_msg(Msg) ->
* > {ok, HSMsg} = eblake2:blake2b(32, salted_msg(Msg)),
* > HSMsg.
* >
* >
* >
* > -spec salted_msg(Message) -> SaltedMessage
* > when Message :: binary(),
* > SaltedMessage :: binary().
* > % @doc Salt the message the way Superhero does before signing.
* > %
* > % See: https://github.com/aeternity/aepp-sdk-js/blob/370f1e30064ad0239ba59931908d9aba0a2e86b6/src/utils/crypto.ts#L171-L175
* >
* > salted_msg(Msg) when is_binary(Msg) ->
* > P = <<"aeternity Signed Message:\n">>,
* > {ok, SP} = btc_varuint_encode(byte_size(P)),
* > {ok, SMsg} = btc_varuint_encode(byte_size(Msg)),
* > <<SP/binary,
* > P/binary,
* > SMsg/binary,
* > Msg/binary>>.
* >
* >
* >
* > -spec btc_varuint_encode(Integer) -> Result
* > when Integer :: integer(),
* > Result :: {ok, Encoded :: binary()}
* > | {error, Reason :: term()}.
* > % @doc Bitcoin varuint encode
* > %
* > % See: https://en.bitcoin.it/wiki/Protocol_documentation#Variable_length_integer
* >
* > btc_varuint_encode(N) when N < 0 ->
* > {error, {negative_N, N}};
* > btc_varuint_encode(N) when N < 16#FD ->
* > {ok, <<N>>};
* > btc_varuint_encode(N) when N =< 16#FFFF ->
* > NBytes = eu(N, 2),
* > {ok, <<16#FD, NBytes/binary>>};
* > btc_varuint_encode(N) when N =< 16#FFFF_FFFF ->
* > NBytes = eu(N, 4),
* > {ok, <<16#FE, NBytes/binary>>};
* > btc_varuint_encode(N) when N < (2 bsl 64) ->
* > NBytes = eu(N, 8),
* > {ok, <<16#FF, NBytes/binary>>}.
* >
* > % eu = encode unsigned (little endian with a given byte width)
* > % means add zero bytes to the end as needed
* > eu(N, Size) ->
* > Bytes = binary:encode_unsigned(N, little),
* > NExtraZeros = Size - byte_size(Bytes),
* > ExtraZeros = << <<0>> || _ <- lists:seq(1, NExtraZeros) >>,
* > <<Bytes/binary, ExtraZeros/binary>>.
* > ```
*/
function
hash_and_salt_msg
(message_str : string)
: Uint8Array
{
let message_bytes : Uint8Array = vdk_binary.encode_utf8(message_str);
return blakejs.blake2b(salt_msg(message_bytes), // bytes to hash
undefined, // key (optional)
32); // resulting byte length
}
/**
* salt the message
*
* ```erlang
* -spec salted_msg(Message) -> SaltedMessage
* when Message :: binary(),
* SaltedMessage :: binary().
* % @doc Salt the message the way Superhero does before signing.
* %
* % See: https://github.com/aeternity/aepp-sdk-js/blob/370f1e30064ad0239ba59931908d9aba0a2e86b6/src/utils/crypto.ts#L171-L175
*
* salted_msg(Msg) when is_binary(Msg) ->
* P = <<"aeternity Signed Message:\n">>,
* {ok, SP} = btc_varuint_encode(byte_size(P)),
* {ok, SMsg} = btc_varuint_encode(byte_size(Msg)),
* <<SP/binary,
* P/binary,
* SMsg/binary,
* Msg/binary>>.
* ```
*/
function
salt_msg
(msg_bytes : Uint8Array)
: Uint8Array
{
let prefix_str : string = 'aeternity Signed Message:\n';
let prefix_bytes : Uint8Array = vdk_binary.encode_utf8(prefix_str);
let prefix_size_n : number = prefix_bytes.byteLength;
let prefix_size_bytes : Uint8Array = btc_varuint_encode(prefix_size_n);
let msg_size_n : number = msg_bytes.byteLength;
let msg_size_bytes : Uint8Array = btc_varuint_encode(msg_size_n);
return vdk_binary.bytes_concat_arr([prefix_size_bytes,
prefix_bytes,
msg_size_bytes,
msg_bytes]);
}
/**
* btc varuint encoding
*
* function is the following Erlang code translated into TS
*
* ```erlang
* -spec btc_varuint_encode(Integer) -> Result
* when Integer :: integer(),
* Result :: {ok, Encoded :: binary()}
* | {error, Reason :: term()}.
* % @doc Bitcoin varuint encode
* %
* % See: https://en.bitcoin.it/wiki/Protocol_documentation#Variable_length_integer
*
* btc_varuint_encode(N) when N < 0 ->
* {error, {negative_N, N}};
* btc_varuint_encode(N) when N < 16#FD ->
* {ok, <<N>>};
* btc_varuint_encode(N) when N =< 16#FFFF ->
* NBytes = eu(N, 2),
* {ok, <<16#FD, NBytes/binary>>};
* btc_varuint_encode(N) when N =< 16#FFFF_FFFF ->
* NBytes = eu(N, 4),
* {ok, <<16#FE, NBytes/binary>>};
* btc_varuint_encode(N) when N < (2 bsl 64) ->
* NBytes = eu(N, 8),
* {ok, <<16#FF, NBytes/binary>>}.
* ```
*/
function
btc_varuint_encode
(n : number)
: Uint8Array
{
if
(n < 0) {
throw new Error('n < 0');
}
else if
(n < 0xFD) {
return new Uint8Array([n]);
}
else if
(n < 0xFFFF) {
let prefix : Uint8Array = new Uint8Array([0xFD]);
let n_bytes : Uint8Array = eu(n, 2);
return vdk_binary.bytes_concat(prefix, n_bytes);
}
else if
(n < 0xFFFF_FFFF) {
let prefix : Uint8Array = new Uint8Array([0xFE]);
let n_bytes : Uint8Array = eu(n, 4);
return vdk_binary.bytes_concat(prefix, n_bytes);
}
else {
let prefix : Uint8Array = new Uint8Array([0xFF]);
let n_bytes : Uint8Array = eu(n, 8);
return vdk_binary.bytes_concat(prefix, n_bytes);
}
}
/**
* unsigned integer little endian encoding with a given byte width
*
* @internal
*/
function
eu
(n : number,
byte_width : number)
: Uint8Array
{
// endianness is byte-level not bit-level
// 3> binary:encode_unsigned(258, big).
// <<1,2>>
// 4> binary:encode_unsigned(258, little).
// <<2,1>>
// first encode n as little endian
let n_bytes : Uint8Array = vdk_binary.bigint_to_bytes_little(BigInt(n));
// figure out how much padding we need
let num_extra_zeros : number = byte_width - n_bytes.byteLength;
let extra_zeros : Uint8Array = vdk_binary.bytes_zeros(num_extra_zeros);
// in little endian, padding 0s go on the right
return vdk_binary.bytes_concat(n_bytes, extra_zeros);
}