@novasamatech/statement-store 0.8.12 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/crypto.js +2 -1
- package/dist/model/session.d.ts +1 -1
- package/dist/model/session.js +1 -1
- package/dist/model/sessionAccount.js +2 -1
- package/dist/session/encyption.js +7 -7
- package/dist/session/encyption.spec.d.ts +1 -0
- package/dist/session/encyption.spec.js +43 -0
- package/dist/session/scale/statementData.js +2 -1
- package/dist/session/session.spec.js +2 -1
- package/package.json +3 -3
package/dist/crypto.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { blake2b } from '@noble/hashes/blake2.js';
|
|
2
|
+
import { Bytes } from '@novasamatech/scale';
|
|
2
3
|
import { deriveSlotAccountPublicKey as deriveSlotPublicKey, ensureSubstrateSlotSr25519Ready, signSlotAccountSecret as signSlotSecret, verifySlotAccountSignature as verifySlotSignature, } from '@novasamatech/substrate-slot-sr25519-wasm';
|
|
3
4
|
import { entropyToMiniSecret } from '@polkadot-labs/hdkd-helpers';
|
|
4
5
|
import { HDKD as sr25519HDKD, secretFromSeed as sr25519SecretFromSeed } from '@scure/sr25519';
|
|
5
|
-
import {
|
|
6
|
+
import { str, u64 } from 'scale-ts';
|
|
6
7
|
import { substrateSr25519PublicKey, substrateSr25519Sign, substrateSr25519Verify } from './substrateSr25519.js';
|
|
7
8
|
export { ensureSubstrateSlotSr25519Ready };
|
|
8
9
|
export { ensureSubstrateSr25519Ready } from './substrateSr25519.js';
|
package/dist/model/session.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Branded } from '../types.js';
|
|
2
2
|
import type { SessionAccount } from './sessionAccount.js';
|
|
3
3
|
export type SessionId = Branded<Uint8Array, 'SessionId'>;
|
|
4
|
-
export declare const SessionIdCodec: import("scale
|
|
4
|
+
export declare const SessionIdCodec: import("@novasamatech/scale").BytesCodec<number>;
|
|
5
5
|
export declare function createSessionId(sharedSecret: Uint8Array, accountA: SessionAccount, accountB: SessionAccount): SessionId;
|
package/dist/model/session.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { Bytes } from '@novasamatech/scale';
|
|
1
2
|
import { mergeUint8 } from 'polkadot-api/utils';
|
|
2
|
-
import { Bytes } from 'scale-ts';
|
|
3
3
|
import { khash, stringToBytes } from '../crypto.js';
|
|
4
4
|
export const SessionIdCodec = Bytes(32);
|
|
5
5
|
export function createSessionId(sharedSecret, accountA, accountB) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { Bytes
|
|
1
|
+
import { Bytes } from '@novasamatech/scale';
|
|
2
|
+
import { Option, Struct, str } from 'scale-ts';
|
|
2
3
|
import { BrandedBytesCodec } from '../crypto.js';
|
|
3
4
|
export const AccountIdCodec = BrandedBytesCodec(32);
|
|
4
5
|
export function createAccountId(value) {
|
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { chacha20poly1305 } from '@noble/ciphers/chacha.js';
|
|
2
2
|
import { hkdf } from '@noble/hashes/hkdf.js';
|
|
3
3
|
import { sha256 } from '@noble/hashes/sha2.js';
|
|
4
4
|
import { randomBytes } from '@noble/hashes/utils.js';
|
|
5
5
|
import { Result, fromThrowable } from 'neverthrow';
|
|
6
6
|
import { mergeUint8 } from 'polkadot-api/utils';
|
|
7
7
|
export function createEncryption(sharedSecret) {
|
|
8
|
-
const salt = new Uint8Array(); // secure enough since
|
|
8
|
+
const salt = new Uint8Array(); // secure enough since the X25519 shared secret provides full entropy
|
|
9
9
|
const info = new Uint8Array(); // no need to introduce any context
|
|
10
|
-
const
|
|
10
|
+
const aeadKey = hkdf(sha256, sharedSecret, salt, info, 32);
|
|
11
11
|
return {
|
|
12
12
|
encrypt: fromThrowable(cipherText => {
|
|
13
13
|
const nonce = randomBytes(12);
|
|
14
|
-
const
|
|
15
|
-
return mergeUint8([nonce,
|
|
14
|
+
const aead = chacha20poly1305(aeadKey, nonce);
|
|
15
|
+
return mergeUint8([nonce, aead.encrypt(cipherText)]);
|
|
16
16
|
}),
|
|
17
17
|
decrypt: fromThrowable(encryptedMessage => {
|
|
18
18
|
const nonce = encryptedMessage.slice(0, 12);
|
|
19
19
|
const cipherText = encryptedMessage.slice(12);
|
|
20
|
-
const
|
|
21
|
-
return
|
|
20
|
+
const aead = chacha20poly1305(aeadKey, nonce);
|
|
21
|
+
return aead.decrypt(cipherText);
|
|
22
22
|
}),
|
|
23
23
|
};
|
|
24
24
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { chacha20poly1305 } from '@noble/ciphers/chacha.js';
|
|
2
|
+
import { hkdf } from '@noble/hashes/hkdf.js';
|
|
3
|
+
import { sha256 } from '@noble/hashes/sha2.js';
|
|
4
|
+
import { randomBytes } from '@noble/hashes/utils.js';
|
|
5
|
+
import { describe, expect, it } from 'vitest';
|
|
6
|
+
import { createEncryption } from './encyption.js';
|
|
7
|
+
const deriveAeadKey = (sharedSecret) => hkdf(sha256, sharedSecret, new Uint8Array(), new Uint8Array(), 32);
|
|
8
|
+
describe('statement-store message encryption', () => {
|
|
9
|
+
it('round-trips a message', () => {
|
|
10
|
+
const sharedSecret = randomBytes(32);
|
|
11
|
+
const encryption = createEncryption(sharedSecret);
|
|
12
|
+
const plaintext = new TextEncoder().encode('hello statement');
|
|
13
|
+
const encrypted = encryption.encrypt(plaintext)._unsafeUnwrap();
|
|
14
|
+
const decrypted = encryption.decrypt(encrypted)._unsafeUnwrap();
|
|
15
|
+
expect(decrypted).toEqual(plaintext);
|
|
16
|
+
});
|
|
17
|
+
it('produces ChaCha20-Poly1305 ciphertext decryptable by an external ChaCha20-Poly1305 reader', () => {
|
|
18
|
+
const sharedSecret = randomBytes(32);
|
|
19
|
+
const plaintext = new TextEncoder().encode('cross-decrypt me');
|
|
20
|
+
const encrypted = createEncryption(sharedSecret).encrypt(plaintext)._unsafeUnwrap();
|
|
21
|
+
const nonce = encrypted.slice(0, 12);
|
|
22
|
+
const body = encrypted.slice(12);
|
|
23
|
+
const aeadKey = deriveAeadKey(sharedSecret);
|
|
24
|
+
const decrypted = chacha20poly1305(aeadKey, nonce).decrypt(body);
|
|
25
|
+
expect(decrypted).toEqual(plaintext);
|
|
26
|
+
});
|
|
27
|
+
it('decrypts a ChaCha20-Poly1305 ciphertext built externally (nonce || ct || tag framing)', () => {
|
|
28
|
+
const sharedSecret = randomBytes(32);
|
|
29
|
+
const plaintext = new TextEncoder().encode('external chacha');
|
|
30
|
+
const aeadKey = deriveAeadKey(sharedSecret);
|
|
31
|
+
const nonce = randomBytes(12);
|
|
32
|
+
const body = chacha20poly1305(aeadKey, nonce).encrypt(plaintext);
|
|
33
|
+
const wire = new Uint8Array([...nonce, ...body]);
|
|
34
|
+
const decrypted = createEncryption(sharedSecret).decrypt(wire)._unsafeUnwrap();
|
|
35
|
+
expect(decrypted).toEqual(plaintext);
|
|
36
|
+
});
|
|
37
|
+
it('fails to decrypt with a different shared secret', () => {
|
|
38
|
+
const plaintext = new TextEncoder().encode('secret');
|
|
39
|
+
const encrypted = createEncryption(randomBytes(32)).encrypt(plaintext)._unsafeUnwrap();
|
|
40
|
+
const result = createEncryption(randomBytes(32)).decrypt(encrypted);
|
|
41
|
+
expect(result.isErr()).toBe(true);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { Bytes
|
|
1
|
+
import { Bytes } from '@novasamatech/scale';
|
|
2
|
+
import { Enum, Struct, Vector, enhanceCodec, str, u8 } from 'scale-ts';
|
|
2
3
|
export const ResponseCode = enhanceCodec(u8, error => {
|
|
3
4
|
switch (error) {
|
|
4
5
|
case 'success':
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { Bytes } from '@novasamatech/scale';
|
|
1
2
|
import { createExpiryFromDuration } from '@novasamatech/sdk-statement';
|
|
2
3
|
import { ResultAsync, err, errAsync, ok, okAsync } from 'neverthrow';
|
|
3
|
-
import {
|
|
4
|
+
import { Struct, str } from 'scale-ts';
|
|
4
5
|
import { describe, expect, it, vi } from 'vitest';
|
|
5
6
|
import { createInMemoryStatementStore } from '../adapter/inMemory.js';
|
|
6
7
|
import { AccountFullError, ExpiryTooLowError } from '../adapter/types.js';
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@novasamatech/statement-store",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.9.0",
|
|
5
5
|
"description": "Statement store integration",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"repository": {
|
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
"README.md"
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@novasamatech/scale": "0.
|
|
28
|
+
"@novasamatech/scale": "0.9.0",
|
|
29
29
|
"@novasamatech/sdk-statement": "^0.6.0",
|
|
30
|
-
"@novasamatech/substrate-slot-sr25519-wasm": "0.
|
|
30
|
+
"@novasamatech/substrate-slot-sr25519-wasm": "0.9.0",
|
|
31
31
|
"@polkadot-api/substrate-bindings": "^0.20.3",
|
|
32
32
|
"@polkadot-api/substrate-client": "^0.7.0",
|
|
33
33
|
"@polkadot-labs/hdkd-helpers": "^0.0.31",
|