mirror of
https://github.com/sonr-io/sonr.git
synced 2026-08-04 02:11:40 +00:00
@@ -0,0 +1,83 @@
|
||||
import { hmac } from '@noble/hashes/hmac';
|
||||
import { keccak_256 } from '@noble/hashes/sha3';
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
import * as secp256k1 from '@noble/secp256k1';
|
||||
import { utf8 } from '@scure/base';
|
||||
import type { CosmosTxV1beta1SignDoc as SignDoc } from '@sonr.io/es/protobufs';
|
||||
import type { StdSignDoc } from '@sonr.io/es/registry';
|
||||
|
||||
import { serialiseSignDoc } from './serialise';
|
||||
|
||||
function sign(
|
||||
bytes: Uint8Array,
|
||||
privateKey: Uint8Array,
|
||||
type: 'secp256k1' | 'ethsecp256k1'
|
||||
): Uint8Array {
|
||||
// Required polyfills for secp256k1 that must be called before any sign ops.
|
||||
// See: https://github.com/paulmillr/noble-secp256k1?tab=readme-ov-file#usage
|
||||
secp256k1.etc.hmacSha256Sync = (k, ...m) => hmac(sha256, k, secp256k1.etc.concatBytes(...m));
|
||||
const hash = type === 'secp256k1' ? sha256(bytes) : keccak_256(bytes);
|
||||
return secp256k1.sign(hash, privateKey).toCompactRawBytes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Signs the given amino-encoded `stdSignDoc` with the given `privateKey` using
|
||||
* secp256k1, and returns the signature bytes. For Injective, the `type` param
|
||||
* must be set to `ethsecp256k1`.
|
||||
*/
|
||||
export function signAmino(
|
||||
stdSignDoc: StdSignDoc,
|
||||
privateKey: Uint8Array,
|
||||
type: 'secp256k1' | 'ethsecp256k1' = 'secp256k1'
|
||||
): Uint8Array {
|
||||
return sign(serialiseSignDoc(stdSignDoc), privateKey, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Signs the given proto-encoded `signDoc` with the given `privateKey` using
|
||||
* secp256k1, and returns the signature bytes. For Injective, the `type` param
|
||||
* must be set to `ethsecp256k1`.
|
||||
*/
|
||||
export function signDirect(
|
||||
signDoc: SignDoc,
|
||||
privateKey: Uint8Array,
|
||||
type: 'secp256k1' | 'ethsecp256k1' = 'secp256k1'
|
||||
): Uint8Array {
|
||||
return sign(signDoc.toBinary(), privateKey, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hashes and returns the digest of the given EIP191 `message` bytes.
|
||||
*/
|
||||
export function hashEthArbitraryMessage(message: Uint8Array): Uint8Array {
|
||||
return keccak_256(
|
||||
Uint8Array.from([
|
||||
...utf8.decode('\x19Ethereum Signed Message:\n'),
|
||||
...utf8.decode(message.length.toString()),
|
||||
...message,
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recovers and returns the secp256k1 public key of the signer given the arbitrary
|
||||
* `message` and `signature` that was signed using EIP191.
|
||||
*/
|
||||
export function recoverPubKeyFromEthSignature(
|
||||
message: Uint8Array,
|
||||
signature: Uint8Array
|
||||
): Uint8Array {
|
||||
if (signature.length !== 65) {
|
||||
throw new Error('Invalid signature');
|
||||
}
|
||||
const r = signature.slice(0, 32);
|
||||
const s = signature.slice(32, 64);
|
||||
const v = signature[64];
|
||||
// Adapted from https://github.com/ethers-io/ethers.js/blob/6017d3d39a4d428793bddae33d82fd814cacd878/src.ts/crypto/signature.ts#L255-L265
|
||||
const yParity = v <= 1 ? v : (v + 1) % 2;
|
||||
const secpSignature = secp256k1.Signature.fromCompact(
|
||||
Uint8Array.from([...r, ...s])
|
||||
).addRecoveryBit(yParity);
|
||||
const digest = hashEthArbitraryMessage(message);
|
||||
return secpSignature.recoverPublicKey(digest).toRawBytes(true);
|
||||
}
|
||||
Reference in New Issue
Block a user