Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
f533319
Contextual Wallet API
ehanoc Aug 29, 2023
2a8eeb9
Merge branch 'main' of github.com:algorandfoundation/ARCs into dev_arc78
ehanoc Aug 29, 2023
fcdd0e4
Merge branch 'main' into pr/239
SudoWeezy Aug 30, 2023
ba9a4c1
Assign number + fix linting
SudoWeezy Aug 30, 2023
62f7bf6
Merge branch 'wallet-api-context' of github.com:ehanoc/ARCs into dev_…
ehanoc Sep 25, 2023
585d48a
Update specification keygen & sign
ehanoc Sep 25, 2023
5874b3f
Update authors
ehanoc Sep 25, 2023
2488fa5
doc: Update ARC52 API and description
ehanoc Oct 25, 2023
048e508
Fix lint + add Rational, Reference Implementation & Security Consider…
SudoWeezy Oct 25, 2023
76899c7
ECDH section and examples added
ehanoc Oct 27, 2023
3f4fc71
Add BIP44 link
ehanoc Oct 27, 2023
aa256ab
Rationale section after spec
ehanoc Oct 27, 2023
1fb8d83
Remove dependency on ARC44
ehanoc Oct 27, 2023
0107c5c
Add reference implementation
ehanoc Oct 27, 2023
326445b
BIP32-Ed25519 by the book impl and test vectors. Reference Paper incl…
ehanoc Oct 29, 2023
8feb165
Update README with reference impl link
ehanoc Oct 29, 2023
9ea1f1d
Update use cases to reject regular transaction signing
ehanoc Nov 1, 2023
ca90868
Small refactor
ehanoc Nov 1, 2023
8e29901
Test Vectors against known ed25519 javascript lib
ehanoc Nov 3, 2023
8ad26e3
Test Vectors bip39 bip32-ed25519 bip44
ehanoc Nov 3, 2023
6692a77
Authentication challenge Schema example. Added cases for when encodin…
ehanoc Nov 4, 2023
f459553
Link schema examples on spec
ehanoc Nov 8, 2023
ea9dd28
Fix: SHA256(0x01||seed), 0x01 was 0x00 array
ehanoc Nov 27, 2023
62b841e
Fix Html link to allow access from generated website
SudoWeezy Jan 11, 2024
660e82f
Updating ECDH tests so that bob has different rootKey than Alice
ehanoc Jan 24, 2024
b38ef81
Merge branch 'wallet-api-context' of github.com:ehanoc/ARCs into dev_…
ehanoc Jan 24, 2024
4efe105
Fix: slicing scalar too soon before signing
ehanoc Feb 27, 2024
f36cf8b
chore: specify types
ehanoc Feb 27, 2024
8e26a6f
fix: ECDH using common Curve25519 point and concatenation into hash f…
ehanoc Feb 27, 2024
0192f5c
chore: comment in ECDH function
ehanoc Feb 27, 2024
d44a8e9
feat: simplify signData
HashMapsData2Value Feb 27, 2024
5766c5f
chore: clarifies tests, small refactor of ecdh
HashMapsData2Value Mar 4, 2024
3ab2169
fix: remove commented out test, for now
HashMapsData2Value Mar 4, 2024
f66b436
chore: Refactor, include tweetnacl to verify correctness
ehanoc Mar 13, 2024
950020c
1-1 feature parity with Kotlin
ori-shem-tov Mar 25, 2024
87d5291
add public key verification to trnasaction signing test
ori-shem-tov Mar 26, 2024
4319a82
Merge pull request #1 from ori-shem-tov/wallet-api-context
HashMapsData2Value Mar 26, 2024
6e8337c
Revert "1-1 feature parity with Kotlin"
ehanoc Mar 26, 2024
8b4de1d
Merge pull request #2 from ehanoc/revert-1-wallet-api-context
ehanoc Mar 26, 2024
ad3642a
1-1 feature parity with Kotlin
ori-shem-tov Mar 25, 2024
a151b98
remove algosdk dep
ori-shem-tov Mar 27, 2024
718e059
Merge pull request #3 from ori-shem-tov/wallet-api-context
ehanoc Mar 27, 2024
421089f
Update assets/arc-0052/contextual.api.crypto.ts
ehanoc Mar 27, 2024
43aa9c0
Update assets/arc-0052/contextual.api.crypto.ts
ehanoc Mar 27, 2024
ced1c70
feat: support to Peikerts bip32ed25519 ammendent to derivations
ehanoc Apr 24, 2024
b84c6be
feat: support to Peikerts bip32ed25519 ammendent to derivations
ehanoc Apr 24, 2024
1b51687
doc: Update README with new test vectors and details
ehanoc Apr 25, 2024
333601d
fix: package.json, logs, run all tests
ehanoc Apr 25, 2024
e008a3d
chore: Add public derivation tests and use cases. Check for correctne…
ehanoc Apr 25, 2024
5b1a230
chore: rearranged lines to align with steps in paper
HashMapsData2Value Apr 26, 2024
c068a44
chore: clarify childChainCode naming
HashMapsData2Value Apr 26, 2024
a6ffb6e
chore: remove whitespace
HashMapsData2Value Apr 26, 2024
6a02c3f
fix: zero out the most significant bits in a little endian array. Wro…
ehanoc May 6, 2024
4bdb38f
temp: tests for break levels derivation
ehanoc May 20, 2024
92a8b4e
Detect when scalar >= 2^255, stop derivation
ehanoc Jun 13, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 90 additions & 25 deletions assets/arc-0052/bip32-ed25519.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,36 @@ export function fromSeed(seed: Buffer): Uint8Array {
return new Uint8Array(Buffer.concat([kL, kR, c]));
}

/**
* This function takes an array of up to 256 bits and sets the last g trailing bits to zero
*
* @param array - An array of up to 256 bits
* @param g - The number of bits to zero
* @returns - The array with the last g bits set to zero
*/
export function trunc_256_minus_g_bits(array: Uint8Array, g: number): Uint8Array {
if (g < 0 || g > 256) {
throw new Error("Number of bits to zero must be between 0 and 256.");
}

let remainingBits = g;

// Start from the last byte and move backward
for (let i = array.length - 1; i >= 0 && remainingBits > 0; i--) {
if (remainingBits >= 8) {
// If more than 8 bits remain to be zeroed, zero the entire byte
array[i] = 0;
remainingBits -= 8;
} else {
// Zero only the required bits in the last affected byte
array[i] &= ~(0xFF >> (8 - remainingBits)); // Mask to zero only the last remainingBits
break;
}
}

return array
}

/**
* @see section V. BIP32-Ed25519: Specification;
*
Expand All @@ -53,38 +83,62 @@ export function fromSeed(seed: Buffer): Uint8Array {
*
* @param extendedKey - extended key (kL, kR, c) where kL is the left 32 bytes of the root key the scalar (pvtKey). kR is the right 32 bytes of the root key, and c is the chain code. Total 96 bytes
* @param index - index of the child key
* @param g - Defines how many bits to zero in the left 32 bytes of the child key. Standard BIP32-ed25519 derivations use 32 bits.
* @returns - (kL, kR, c) where kL is the left 32 bytes of the child key (the new scalar), kR is the right 32 bytes of the child key, and c is the chain code. Total 96 bytes
*/
export function deriveChildNodePrivate(
extendedKey: Uint8Array,
index: number
index: number,
g: number = 9
): Uint8Array {
const kl: Buffer = Buffer.from(extendedKey.subarray(0, 32));
const kr: Buffer = Buffer.from(extendedKey.subarray(32, 64));
const kL: Buffer = Buffer.from(extendedKey.subarray(0, 32));
const kR: Buffer = Buffer.from(extendedKey.subarray(32, 64));
const cc: Uint8Array = extendedKey.subarray(64, 96);

const { z, childChainCode } = index < 0x80000000 ? derivedNonHardened(kl, cc, index) : deriveHardened(kl, kr, cc, index);
const { z, childChainCode } = index < 0x80000000 ? derivedNonHardened(kL, cc, index) : deriveHardened(kL, kR, cc, index);

const chainCode = childChainCode.subarray(32, 64);
const zl = z.subarray(0, 32);
const zr = z.subarray(32, 64);

// left = kl + 8 * trunc28(zl)
// right = zr + kr

const left = new BN(kl, 16, "le").add(new BN(zl.subarray(0, 28), 16, "le").mul(new BN(8))).toArrayLike(Buffer, "le", 32);
let right = new BN(kr, 16, "le").add(new BN(zr, 16, "le")).toArrayLike(Buffer, "le").slice(0, 32);


const zLeft = z.subarray(0, 32); // 32 bytes
const zRight = z.subarray(32, 64);

// ######################################
// Standard BIP32-ed25519 derivation
// #######################################
// zL = kl + 8 * trunc_keep_28_bytes (z_left_hand_side)
// zR = zr + kr

// ######################################
// Chris Peikert's ammendment to BIP32-ed25519 derivation
// #######################################
// zL = kl + 8 * trunc_256_minus_g_bits (z_left_hand_side, g)
// Needs to satisfy g >= d + 6
//
// D = 2 ^ d , D is the maximum levels of BIP32 derivations to ensure a more secure key derivation


// Picking g == 9 && d == 3
// 256 - 9 == 247 bits (30 bytes + leftover)
// D = 2 ^ 3 == 8 Max Levels of derivations (Although we only need 5 due to BIP44)

// making sure
// g == 9 >= 3 + 6

const zL: Uint8Array = trunc_256_minus_g_bits(zLeft, g);

// zL = kL + 8 * truncated(z_left_hand_side)
// Big Integers + little Endianess
const klBigNum = new BN(kL, 16, "le")
const big8 = new BN(8);
const zlBigNum = new BN(zL, 16, "le");

const left = klBigNum.add(zlBigNum.mul(big8)).toArrayLike(Buffer, "le", 32);

let right = new BN(kR, 16, "le").add(new BN(zRight, 16, "le")).toArrayLike(Buffer, "le").slice(0, 32);

const rightBuffer = Buffer.alloc(32);
Buffer.from(right).copy(rightBuffer, 0, 0, right.length)


// just padding
// if (right.length !== 32) {
// right = Buffer.from(right.toString("hex") + "00", "hex");
// }
Buffer.from(right).copy(rightBuffer, 0, 0, right.length) // padding with zeros if needed

// return (kL, kR, c)
return Buffer.concat([left, rightBuffer, chainCode]);
}

Expand All @@ -97,9 +151,10 @@ export function deriveChildNodePrivate(
*
* @param extendedKey - extend public key (p, c) where p is the public key and c is the chain code. Total 64 bytes
* @param index - unharden index (i < 2^31) of the child key
* @param g - Defines how many bits to zero in the left 32 bytes of the child key. Standard BIP32-ed25519 derivations use 32 bits.
* @returns - 64 bytes, being the 32 bytes of the child key (the new public key) followed by the 32 bytes of the chain code
*/
export function deriveChildNodePublic(extendedKey: Uint8Array, index: number): Uint8Array {
export function deriveChildNodePublic(extendedKey: Uint8Array, index: number, g: number = 9): Uint8Array {
if (index > 0x80000000) throw new Error('can not derive public key with harden')

const pk: Buffer = Buffer.from(extendedKey.subarray(0, 32))
Expand All @@ -118,10 +173,20 @@ export function deriveChildNodePublic(extendedKey: Uint8Array, index: number): U

// Section V. BIP32-Ed25519: Specification; subsection D) Public Child Key Derivation
const chainCode: Buffer = i.subarray(32, 64);
const zl: Buffer = z.subarray(0, 32);

const zL: Uint8Array = trunc_256_minus_g_bits(z.subarray(0, 32), g)

// left = 8 * 28bytesOf(zl)
const left = new BN(zl.subarray(0, 28), 16, 'le').mul(new BN(8)).toArrayLike(Buffer, 'le', 32);
// ######################################
// Standard BIP32-ed25519 derivation
// #######################################
// zL = 8 * 28bytesOf(z_left_hand_side)

// ######################################
// Chris Peikert's ammendment to BIP32-ed25519 derivation
// #######################################
// zL = 8 * trunc_256_minus_g_bits (z_left_hand_side, g)

const left = new BN(zL, 16, 'le').mul(new BN(8)).toArrayLike(Buffer, 'le', 32);

const p: Uint8Array = crypto_scalarmult_ed25519_base_noclamp(left);
return Buffer.concat([crypto_core_ed25519_add(p, pk), chainCode]);
Expand Down
62 changes: 33 additions & 29 deletions assets/arc-0052/contextual.api.crypto.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { CryptoKX, KeyPair, crypto_kx_client_session_keys, crypto_kx_server_session_keys, crypto_scalarmult, crypto_scalarmult_ed25519_base_noclamp, crypto_secretbox_easy, crypto_secretbox_open_easy, crypto_sign_ed25519_pk_to_curve25519, crypto_sign_ed25519_sk_to_curve25519, crypto_sign_keypair, ready, to_base64 } from "libsodium-wrappers-sumo"
import * as bip39 from "bip39"
import { randomBytes } from "crypto"
import { ContextualCryptoApi, ERROR_BAD_DATA, ERROR_TAGS_FOUND, Encoding, KeyContext, SignMetadata, harden } from "./contextual.api.crypto"
import { BIP32DerivationType, ContextualCryptoApi, ERROR_TAGS_FOUND, Encoding, KeyContext, SignMetadata, harden } from "./contextual.api.crypto"
import * as msgpack from "algo-msgpack-with-bigint"
import { fromSeed } from "./bip32-ed25519"
import { sha512_256 } from "js-sha512"
Expand Down Expand Up @@ -50,10 +50,12 @@ describe("Contextual Derivation & Signing", () => {

afterEach(() => {})

// Skipping because we are not diverging from standard BIP32-Ed25519 implementation as we are doing improvements
// Keeping tests so we can always go back and check for correctness
describe("\(JS Library) Reference Implementation alignment with known BIP32-Ed25519 JS LIB", () => {
it("\(OK) BIP32-Ed25519 derive key m'/44'/283'/0'/0/0", async () => {
await ready
const key: Uint8Array = await cryptoService.keyGen(KeyContext.Address, 0, 0)
const key: Uint8Array = await cryptoService.keyGen(KeyContext.Address, 0, 0, BIP32DerivationType.Khovratovich)

const rooKey: Uint8Array = fromSeed(seed)

Expand All @@ -70,7 +72,7 @@ describe("Contextual Derivation & Signing", () => {

it("\(OK) BIP32-Ed25519 derive key m'/44'/283'/0'/0/1", async () => {
await ready
const key: Uint8Array = await cryptoService.keyGen(KeyContext.Address, 0, 1)
const key: Uint8Array = await cryptoService.keyGen(KeyContext.Address, 0, 1, BIP32DerivationType.Khovratovich)

const rooKey: Uint8Array = fromSeed(seed)

Expand All @@ -87,7 +89,7 @@ describe("Contextual Derivation & Signing", () => {

it("\(OK) BIP32-Ed25519 derive PUBLIC key m'/44'/283'/1'/0/1", async () => {
await ready
const key: Uint8Array = await cryptoService.keyGen(KeyContext.Address, 1, 1)
const key: Uint8Array = await cryptoService.keyGen(KeyContext.Address, 1, 1, BIP32DerivationType.Khovratovich)

const rooKey: Uint8Array = fromSeed(seed)

Expand All @@ -112,7 +114,7 @@ describe("Contextual Derivation & Signing", () => {

it("\(OK) BIP32-Ed25519 derive PUBLIC key m'/44'/0'/1'/0/2", async () => {
await ready
const key: Uint8Array = await cryptoService.keyGen(KeyContext.Identity, 1, 2)
const key: Uint8Array = await cryptoService.keyGen(KeyContext.Identity, 1, 2, BIP32DerivationType.Khovratovich)

const rooKey: Uint8Array = fromSeed(seed)

Expand Down Expand Up @@ -147,66 +149,67 @@ describe("Contextual Derivation & Signing", () => {
describe("Soft Derivations", () => {
it("\(OK) Derive m'/44'/283'/0'/0/0 Algorand Address Key", async () => {
const key: Uint8Array = await cryptoService.keyGen(KeyContext.Address, 0, 0)
expect(key).toEqual(new Uint8Array(Buffer.from("62fe832b7ad10544be8337a670435e5064ae4a66e77bd78909765b46b576a6f3", "hex")))
expect(key).toEqual(new Uint8Array(Buffer.from("8ad0bbc42326ac64eb4dbbe40a77518a7fc1d39504b618a4dc85f03b3a921a02", "hex")))
})

it("\(OK) Derive m'/44'/283'/0'/0/1 Algorand Address Key", async () => {
const key: Uint8Array = await cryptoService.keyGen(KeyContext.Address, 0, 1)
expect(key).toEqual(new Uint8Array(Buffer.from("530461002eaccec0c7b5795925aa104a7fb45f85ef0aa95bbb5be93b6f8537ad", "hex")))

expect(key).toEqual(new Uint8Array(Buffer.from("2d3f9e31232bd36e6c0f37597e19c4c0154e58c41bc2b737c7700b683e85d0af", "hex")))
})

it("\(OK) Derive m'/44'/283'/0'/0/2 Algorand Address Key", async () => {
const key: Uint8Array = await cryptoService.keyGen(KeyContext.Address, 0, 2)
expect(key).toEqual(new Uint8Array(Buffer.from("2281c81bee04ee039fa482c283541c6ab06c8324db6f1cc59c68252e1d58bcb3", "hex")))
expect(key).toEqual(new Uint8Array(Buffer.from("96acc17f0c34f6c640d5466988ce59c4da5423b5ec233b7ad2e5c5a3b1b80782", "hex")))
})

})

describe("Hard Derivations", () => {
it("\(OK) Derive m'/44'/283'/1'/0/0 Algorand Address Key", async () => {
const key: Uint8Array = await cryptoService.keyGen(KeyContext.Address, 1, 0)
expect(key).toEqual(new Uint8Array(Buffer.from("9e12643f6c0068dcf53b04daced6f8c1a90ad21c954a66df4140d79303166a67", "hex")))
expect(key).toEqual(new Uint8Array(Buffer.from("fd56577456794efb91e05dc947d26d4864b346d139dfa8fff9b0e1def84b9078", "hex")))
})

it("\(OK) Derive m'/44'/283'/2'/0/1 Algorand Address Key", async () => {
const key: Uint8Array = await cryptoService.keyGen(KeyContext.Address, 2, 1)
expect(key).toEqual(new Uint8Array(Buffer.from("8a5ddf62d51a2c50e51dbad4634356cc72314a81edd917ac91da96477a9fb5b0", "hex")))
expect(key).toEqual(new Uint8Array(Buffer.from("aa03d62057744f4422d70c3a421deae838d8f7546a15f2ada59287569911144c", "hex")))
})

it("\(OK) Derive m'/44'/283'/3'/0/0 Algorand Address Key", async () => {
const key: Uint8Array = await cryptoService.keyGen(KeyContext.Address, 3, 0)
expect(key).toEqual(new Uint8Array(Buffer.from("2358e0f2b465ab3e8f55139d8316654d4be39ebb22367d36409fd02a20b0e017", "hex")))
expect(key).toEqual(new Uint8Array(Buffer.from("303718c23846fdd0f7d9cded69d95c5a72fbb1ccbbea50c865c00c050bb0e68b", "hex")))
})
})
})

describe("Identities", () => {
describe("Soft Derivations", () => {
it("\(OK) Derive m'/44'/0'/0'/0/0 Identity Key", async () => {
const key: Uint8Array = await cryptoService.keyGen(KeyContext.Identity, 0, 0)
expect(key).toEqual(new Uint8Array(Buffer.from("b6d7eea5af0ad83edf4340659e72f0ea2b4566de1fc3b63a40a425aabebe5e49", "hex")))
expect(key).toEqual(new Uint8Array(Buffer.from("844cda69c4ef7c212befaa6733f5e3c0317fc173cb9f14c6cf66a48263e722ec", "hex")))
})

it("\(OK) Derive m'/44'/0'/0'/0/1 Identity Key", async () => {
const key: Uint8Array = await cryptoService.keyGen(KeyContext.Identity, 0, 1)
expect(key).toEqual(new Uint8Array(Buffer.from("b5cec676c5a2129ed1be4223a2702439bbb2462fd77b43f27e2f79fd194a30a2", "hex")))
expect(key).toEqual(new Uint8Array(Buffer.from("a8c6de4e6d2672ad5a804994cf6e481ea7c2c3b1cedc5f51c63b2d0819d503f0", "hex")))
})

it("\(OK) Derive m'/44'/0'/0'/0/2 Identity Key", async () => {
const key: Uint8Array = await cryptoService.keyGen(KeyContext.Identity, 0, 2)
expect(key).toEqual(new Uint8Array(Buffer.from("435e5e3446431d462572abee1b8badb88608906a6af27b8497bccfd503edb6fe", "hex")))
expect(key).toEqual(new Uint8Array(Buffer.from("88e493675894f0ba8472037da40a61a7ed356fd0f24c312a1ec9bb7c052f5d8c", "hex")))
})
})

describe("Hard Derivations", () => {
it("\(OK) Derive m'/44'/0'/1'/0/0 Identity Key", async () => {
const key: Uint8Array = await cryptoService.keyGen(KeyContext.Identity, 1, 0)
expect(key).toEqual(new Uint8Array(Buffer.from("bf63be83fff9bc9d0aebc231d50342110e5220247e50de376b47e154b5d32a3e", "hex")))
expect(key).toEqual(new Uint8Array(Buffer.from("c120ac324985009294f2546463f922a55cd93fb1d209929828d2a952c4581760", "hex")))
})

it("\(OK) Derive m'/44'/0'/2'/0/1 Identity Key", async () => {
const key: Uint8Array = await cryptoService.keyGen(KeyContext.Identity, 2, 1)
expect(key).toEqual(new Uint8Array(Buffer.from("edb10fff24a4745df52f1a0ab1ae71b3752d019c8c2437d46ab8c8e634a74cd4", "hex")))
expect(key).toEqual(new Uint8Array(Buffer.from("82ccd181c1d533828a77218bdff0329966dc506084d5b87a0f2eb6678e53cb21", "hex")))
})
})
})
Expand Down Expand Up @@ -375,10 +378,10 @@ describe("Contextual Derivation & Signing", () => {

describe("signing transactions", () => {
it("\(OK) Sign Transaction", async () => {
const key: Uint8Array = await cryptoService.keyGen(KeyContext.Address, 0, 0)
const key: Uint8Array = await cryptoService.keyGen(KeyContext.Address, 0, 0, BIP32DerivationType.Khovratovich)
// this transaction wes successfully submitted to the network https://testnet.explorer.perawallet.app/tx/UJG3NVCSCW5A63KPV35BPAABLXMXTTEM2CVUKNS4EML3H3EYGMCQ/
const prefixEncodedTx = new Uint8Array(Buffer.from('VFiJo2FtdM0D6KNmZWXNA+iiZnbOAkeSd6NnZW6sdGVzdG5ldC12MS4womdoxCBIY7UYpLPITsgQ8i1PEIHLD3HwWaesIN7GL39w5Qk6IqJsds4CR5Zfo3JjdsQgYv6DK3rRBUS+gzemcENeUGSuSmbne9eJCXZbRrV2pvOjc25kxCBi/oMretEFRL6DN6ZwQ15QZK5KZud714kJdltGtXam86R0eXBlo3BheQ==', 'base64'))
const sig = await cryptoService.signAlgoTransaction(KeyContext.Address, 0, 0, prefixEncodedTx)
const sig = await cryptoService.signAlgoTransaction(KeyContext.Address, 0, 0, prefixEncodedTx, BIP32DerivationType.Khovratovich)
expect(encodeAddress(Buffer.from(key))).toEqual("ML7IGK322ECUJPUDG6THAQ26KBSK4STG4555PCIJOZNUNNLWU3Z3ZFXITA")
expect(nacl.sign.detached.verify(prefixEncodedTx, sig, key)).toBe(true)
})
Expand Down Expand Up @@ -422,7 +425,8 @@ describe("Contextual Derivation & Signing", () => {

// encrypt
const cipherText: Uint8Array = crypto_secretbox_easy(message, nonce, aliceSharedSecret)
expect(cipherText).toEqual(new Uint8Array([251,7,48,58,57,22,135,152,150,116,242,138,26,155,136,252,163,209,7,34,125,135,218,222,102,45,250,55,34]))

expect(cipherText).toEqual(new Uint8Array([158, 107, 5, 77, 134, 215, 212, 90, 192, 34, 131, 39, 160, 252, 74, 194, 129, 54, 249, 113, 128, 241, 213, 244, 98, 55, 46, 233, 7]))
// decrypt
const plainText: Uint8Array = crypto_secretbox_open_easy(cipherText, nonce, bobSharedSecret)
expect(plainText).toEqual(message)
Expand Down
Loading