@atproto/crypto 0.1.1 → 0.2.1

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.
@@ -1 +1,3 @@
1
+ import { SupportedEncodings } from 'uint8arrays/to-string';
1
2
  export declare const multibaseToBytes: (mb: string) => Uint8Array;
3
+ export declare const bytesToMultibase: (mb: Uint8Array, encoding: SupportedEncodings) => string;
@@ -1,20 +1,20 @@
1
1
  import { SupportedEncodings } from 'uint8arrays/util/bases';
2
2
  import { Keypair } from '../types';
3
- export declare type EcdsaKeypairOptions = {
3
+ export declare type P256KeypairOptions = {
4
4
  exportable: boolean;
5
5
  };
6
- export declare class EcdsaKeypair implements Keypair {
6
+ export declare class P256Keypair implements Keypair {
7
+ private privateKey;
8
+ private exportable;
7
9
  jwtAlg: string;
8
10
  private publicKey;
9
- private keypair;
10
- private exportable;
11
- constructor(keypair: CryptoKeyPair, publicKey: Uint8Array, exportable: boolean);
12
- static create(opts?: Partial<EcdsaKeypairOptions>): Promise<EcdsaKeypair>;
13
- static import(jwk: JsonWebKey, opts?: Partial<EcdsaKeypairOptions>): Promise<EcdsaKeypair>;
11
+ constructor(privateKey: Uint8Array, exportable: boolean);
12
+ static create(opts?: Partial<P256KeypairOptions>): Promise<P256Keypair>;
13
+ static import(privKey: Uint8Array | string, opts?: Partial<P256KeypairOptions>): Promise<P256Keypair>;
14
14
  publicKeyBytes(): Uint8Array;
15
15
  publicKeyStr(encoding?: SupportedEncodings): string;
16
16
  did(): string;
17
17
  sign(msg: Uint8Array): Promise<Uint8Array>;
18
- export(): Promise<JsonWebKey>;
18
+ export(): Promise<Uint8Array>;
19
19
  }
20
- export default EcdsaKeypair;
20
+ export default P256Keypair;
@@ -1,4 +1,2 @@
1
- export declare const importKeypairJwk: (jwk: JsonWebKey, exportable?: boolean) => Promise<CryptoKeyPair>;
2
1
  export declare const verifyDidSig: (did: string, data: Uint8Array, sig: Uint8Array) => Promise<boolean>;
3
- export declare const verify: (publicKey: Uint8Array, data: Uint8Array, sig: Uint8Array) => Promise<boolean>;
4
- export declare const importEcdsaPublicKey: (keyBytes: Uint8Array) => Promise<CryptoKey>;
2
+ export declare const verifySig: (publicKey: Uint8Array, data: Uint8Array, sig: Uint8Array) => Promise<boolean>;
package/dist/random.d.ts CHANGED
@@ -1,4 +1,5 @@
1
+ import * as noble from '@noble/hashes/utils';
1
2
  import { SupportedEncodings } from 'uint8arrays/to-string';
2
- export declare const randomBytes: (length: number) => Uint8Array;
3
- export declare const randomIV: () => Uint8Array;
3
+ export declare const randomBytes: typeof noble.randomBytes;
4
4
  export declare const randomStr: (byteLength: number, encoding: SupportedEncodings) => string;
5
+ export declare const randomIntFromSeed: (seed: string, high: number, low?: number) => Promise<number>;
@@ -1 +1,2 @@
1
1
  export declare const verifyDidSig: (did: string, data: Uint8Array, sig: Uint8Array) => Promise<boolean>;
2
+ export declare const verifySig: (publicKey: Uint8Array, data: Uint8Array, sig: Uint8Array) => Promise<boolean>;
package/dist/sha.d.ts CHANGED
@@ -1,3 +1 @@
1
- import { Readable } from 'stream';
2
1
  export declare const sha256: (input: Uint8Array | string) => Promise<Uint8Array>;
3
- export declare const sha256Stream: (stream: Readable) => Promise<Uint8Array>;
package/dist/types.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export interface Signer {
2
+ jwtAlg: string;
2
3
  sign(msg: Uint8Array): Promise<Uint8Array>;
3
4
  }
4
5
  export interface Didable {
package/package.json CHANGED
@@ -1,12 +1,17 @@
1
1
  {
2
2
  "name": "@atproto/crypto",
3
- "version": "0.1.1",
3
+ "version": "0.2.1",
4
4
  "main": "dist/index.js",
5
5
  "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/bluesky-social/atproto.git",
9
+ "directory": "packages/crypto"
10
+ },
6
11
  "scripts": {
7
12
  "test": "jest ",
8
- "prettier": "prettier --check src/",
9
- "prettier:fix": "prettier --write src/",
13
+ "prettier": "prettier --check src/ tests/",
14
+ "prettier:fix": "prettier --write src/ tests/",
10
15
  "lint": "eslint . --ext .ts,.tsx",
11
16
  "lint:fix": "yarn lint --fix",
12
17
  "verify": "run-p prettier lint",
@@ -19,10 +24,8 @@
19
24
  "postpublish": "npm run update-main-to-src"
20
25
  },
21
26
  "dependencies": {
22
- "@noble/secp256k1": "^1.7.0",
23
- "big-integer": "^1.6.51",
24
- "multiformats": "^9.6.4",
25
- "one-webcrypto": "^1.0.3",
27
+ "@noble/curves": "^1.1.0",
28
+ "@noble/hashes": "^1.3.1",
26
29
  "uint8arrays": "3.0.0"
27
30
  }
28
31
  }
package/src/const.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export const P256_DID_PREFIX = new Uint8Array([0x80, 0x24])
2
2
  export const SECP256K1_DID_PREFIX = new Uint8Array([0xe7, 0x01])
3
- export const BASE58_DID_PREFIX = 'did:key:z' // z is the multibase prefix for base58btc byte encoding
3
+ export const BASE58_MULTIBASE_PREFIX = 'z'
4
+ export const DID_KEY_PREFIX = 'did:key:'
4
5
 
5
6
  export const P256_JWT_ALG = 'ES256'
6
7
  export const SECP256K1_JWT_ALG = 'ES256K'
package/src/did.ts CHANGED
@@ -2,21 +2,24 @@ import * as uint8arrays from 'uint8arrays'
2
2
  import * as p256 from './p256/encoding'
3
3
  import * as secp from './secp256k1/encoding'
4
4
  import plugins from './plugins'
5
- import { P256_JWT_ALG, SECP256K1_JWT_ALG } from './const'
5
+ import {
6
+ BASE58_MULTIBASE_PREFIX,
7
+ DID_KEY_PREFIX,
8
+ P256_JWT_ALG,
9
+ SECP256K1_JWT_ALG,
10
+ } from './const'
6
11
 
7
- export const DID_KEY_BASE58_PREFIX = 'did:key:z'
8
-
9
- export type ParsedDidKey = {
12
+ export type ParsedMultikey = {
10
13
  jwtAlg: string
11
14
  keyBytes: Uint8Array
12
15
  }
13
16
 
14
- export const parseDidKey = (did: string): ParsedDidKey => {
15
- if (!did.startsWith(DID_KEY_BASE58_PREFIX)) {
16
- throw new Error(`Incorrect prefix for did:key: ${did}`)
17
+ export const parseMultikey = (multikey: string): ParsedMultikey => {
18
+ if (!multikey.startsWith(BASE58_MULTIBASE_PREFIX)) {
19
+ throw new Error(`Incorrect prefix for multikey: ${multikey}`)
17
20
  }
18
21
  const prefixedBytes = uint8arrays.fromString(
19
- did.slice(DID_KEY_BASE58_PREFIX.length),
22
+ multikey.slice(BASE58_MULTIBASE_PREFIX.length),
20
23
  'base58btc',
21
24
  )
22
25
  const plugin = plugins.find((p) => hasPrefix(prefixedBytes, p.prefix))
@@ -35,7 +38,10 @@ export const parseDidKey = (did: string): ParsedDidKey => {
35
38
  }
36
39
  }
37
40
 
38
- export const formatDidKey = (jwtAlg: string, keyBytes: Uint8Array): string => {
41
+ export const formatMultikey = (
42
+ jwtAlg: string,
43
+ keyBytes: Uint8Array,
44
+ ): string => {
39
45
  const plugin = plugins.find((p) => p.jwtAlg === jwtAlg)
40
46
  if (!plugin) {
41
47
  throw new Error('Unsupported key type')
@@ -47,10 +53,21 @@ export const formatDidKey = (jwtAlg: string, keyBytes: Uint8Array): string => {
47
53
  }
48
54
  const prefixedBytes = uint8arrays.concat([plugin.prefix, keyBytes])
49
55
  return (
50
- DID_KEY_BASE58_PREFIX + uint8arrays.toString(prefixedBytes, 'base58btc')
56
+ BASE58_MULTIBASE_PREFIX + uint8arrays.toString(prefixedBytes, 'base58btc')
51
57
  )
52
58
  }
53
59
 
60
+ export const parseDidKey = (did: string): ParsedMultikey => {
61
+ if (!did.startsWith(DID_KEY_PREFIX)) {
62
+ throw new Error(`Incorrect prefix for did:key: ${did}`)
63
+ }
64
+ return parseMultikey(did.slice(DID_KEY_PREFIX.length))
65
+ }
66
+
67
+ export const formatDidKey = (jwtAlg: string, keyBytes: Uint8Array): string => {
68
+ return DID_KEY_PREFIX + formatMultikey(jwtAlg, keyBytes)
69
+ }
70
+
54
71
  const hasPrefix = (bytes: Uint8Array, prefix: Uint8Array): boolean => {
55
72
  return uint8arrays.equals(prefix, bytes.subarray(0, prefix.byteLength))
56
73
  }
package/src/index.ts CHANGED
@@ -1,4 +1,3 @@
1
- export * from './aes'
2
1
  export * from './const'
3
2
  export * from './did'
4
3
  export * from './multibase'
package/src/multibase.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import * as uint8arrays from 'uint8arrays'
2
+ import { SupportedEncodings } from 'uint8arrays/to-string'
2
3
 
3
4
  export const multibaseToBytes = (mb: string): Uint8Array => {
4
5
  const base = mb[0]
@@ -24,3 +25,29 @@ export const multibaseToBytes = (mb: string): Uint8Array => {
24
25
  throw new Error(`Unsupported multibase: :${mb}`)
25
26
  }
26
27
  }
28
+
29
+ export const bytesToMultibase = (
30
+ mb: Uint8Array,
31
+ encoding: SupportedEncodings,
32
+ ): string => {
33
+ switch (encoding) {
34
+ case 'base16':
35
+ return 'f' + uint8arrays.toString(mb, encoding)
36
+ case 'base16upper':
37
+ return 'F' + uint8arrays.toString(mb, encoding)
38
+ case 'base32':
39
+ return 'b' + uint8arrays.toString(mb, encoding)
40
+ case 'base32upper':
41
+ return 'B' + uint8arrays.toString(mb, encoding)
42
+ case 'base58btc':
43
+ return 'z' + uint8arrays.toString(mb, encoding)
44
+ case 'base64':
45
+ return 'm' + uint8arrays.toString(mb, encoding)
46
+ case 'base64url':
47
+ return 'u' + uint8arrays.toString(mb, encoding)
48
+ case 'base64urlpad':
49
+ return 'U' + uint8arrays.toString(mb, encoding)
50
+ default:
51
+ throw new Error(`Unsupported multibase: :${mb}`)
52
+ }
53
+ }
@@ -1,81 +1,14 @@
1
- import bigInt from 'big-integer'
2
- import * as uint8arrays from 'uint8arrays'
1
+ import { p256 } from '@noble/curves/p256'
3
2
 
4
- // PUBLIC KEY COMPRESSION
5
- // ------------------------
6
-
7
- // Compression & Decompression algos from:
8
- // https://stackoverflow.com/questions/48521840/biginteger-to-a-uint8array-of-bytes
9
-
10
- // Public key compression for NIST P-256
11
3
  export const compressPubkey = (pubkeyBytes: Uint8Array): Uint8Array => {
12
- if (pubkeyBytes.length !== 65) {
13
- throw new Error('Expected 65 byte pubkey')
14
- } else if (pubkeyBytes[0] !== 0x04) {
15
- throw new Error('Expected first byte to be 0x04')
16
- }
17
- // first byte is a prefix
18
- const x = pubkeyBytes.slice(1, 33)
19
- const y = pubkeyBytes.slice(33, 65)
20
- const out = new Uint8Array(x.length + 1)
21
-
22
- out[0] = 2 + (y[y.length - 1] & 1)
23
- out.set(x, 1)
24
-
25
- return out
4
+ const point = p256.ProjectivePoint.fromHex(pubkeyBytes)
5
+ return point.toRawBytes(true)
26
6
  }
27
7
 
28
- // Public key decompression for NIST P-256
29
8
  export const decompressPubkey = (compressed: Uint8Array): Uint8Array => {
30
9
  if (compressed.length !== 33) {
31
10
  throw new Error('Expected 33 byte compress pubkey')
32
- } else if (compressed[0] !== 0x02 && compressed[0] !== 0x03) {
33
- throw new Error('Expected first byte to be 0x02 or 0x03')
34
- }
35
- // Consts for P256 curve
36
- const two = bigInt(2)
37
- // 115792089210356248762697446949407573530086143415290314195533631308867097853951
38
- const prime = two
39
- .pow(256)
40
- .subtract(two.pow(224))
41
- .add(two.pow(192))
42
- .add(two.pow(96))
43
- .subtract(1)
44
- const b = bigInt(
45
- '41058363725152142129326129780047268409114441015993725554835256314039467401291',
46
- )
47
-
48
- // Pre-computed value, or literal
49
- const pIdent = prime.add(1).divide(4) // 28948022302589062190674361737351893382521535853822578548883407827216774463488
50
-
51
- // This value must be 2 or 3. 4 indicates an uncompressed key, and anything else is invalid.
52
- const signY = bigInt(compressed[0] - 2)
53
- const x = compressed.slice(1)
54
- const xBig = bigInt(uint8arrays.toString(x, 'base10'))
55
-
56
- // y^2 = x^3 - 3x + b
57
- const maybeY = xBig
58
- .pow(3)
59
- .subtract(xBig.multiply(3))
60
- .add(b)
61
- .modPow(pIdent, prime)
62
-
63
- let yBig
64
- // If the parity matches, we found our root, otherwise it's the other root
65
- if (maybeY.mod(2).equals(signY)) {
66
- yBig = maybeY
67
- } else {
68
- // y = prime - y
69
- yBig = prime.subtract(maybeY)
70
11
  }
71
- const y = uint8arrays.fromString(yBig.toString(10), 'base10')
72
-
73
- // left-pad for smaller than 32 byte y
74
- const offset = 32 - y.length
75
- const yPadded = new Uint8Array(32)
76
- yPadded.set(y, offset)
77
-
78
- // concat coords & prepend P-256 prefix
79
- const publicKey = uint8arrays.concat([[0x04], x, yPadded])
80
- return publicKey
12
+ const point = p256.ProjectivePoint.fromHex(compressed)
13
+ return point.toRawBytes(false)
81
14
  }
@@ -1,54 +1,41 @@
1
- import { webcrypto } from 'one-webcrypto'
1
+ import { p256 } from '@noble/curves/p256'
2
+ import { sha256 } from '@noble/hashes/sha256'
2
3
  import * as uint8arrays from 'uint8arrays'
3
4
  import { SupportedEncodings } from 'uint8arrays/util/bases'
4
5
  import * as did from '../did'
5
- import * as operations from './operations'
6
6
  import { P256_JWT_ALG } from '../const'
7
7
  import { Keypair } from '../types'
8
8
 
9
- export type EcdsaKeypairOptions = {
9
+ export type P256KeypairOptions = {
10
10
  exportable: boolean
11
11
  }
12
12
 
13
- export class EcdsaKeypair implements Keypair {
13
+ export class P256Keypair implements Keypair {
14
14
  jwtAlg = P256_JWT_ALG
15
15
  private publicKey: Uint8Array
16
- private keypair: CryptoKeyPair
17
- private exportable: boolean
18
16
 
19
- constructor(
20
- keypair: CryptoKeyPair,
21
- publicKey: Uint8Array,
22
- exportable: boolean,
23
- ) {
24
- this.keypair = keypair
25
- this.publicKey = publicKey
26
- this.exportable = exportable
17
+ constructor(private privateKey: Uint8Array, private exportable: boolean) {
18
+ this.publicKey = p256.getPublicKey(privateKey)
27
19
  }
28
20
 
29
21
  static async create(
30
- opts?: Partial<EcdsaKeypairOptions>,
31
- ): Promise<EcdsaKeypair> {
22
+ opts?: Partial<P256KeypairOptions>,
23
+ ): Promise<P256Keypair> {
32
24
  const { exportable = false } = opts || {}
33
- const keypair = await webcrypto.subtle.generateKey(
34
- { name: 'ECDSA', namedCurve: 'P-256' },
35
- exportable,
36
- ['sign', 'verify'],
37
- )
38
- const pubkeyBuf = await webcrypto.subtle.exportKey('raw', keypair.publicKey)
39
- const pubkeyBytes = new Uint8Array(pubkeyBuf)
40
- return new EcdsaKeypair(keypair, pubkeyBytes, exportable)
25
+ const privKey = p256.utils.randomPrivateKey()
26
+ return new P256Keypair(privKey, exportable)
41
27
  }
42
28
 
43
29
  static async import(
44
- jwk: JsonWebKey,
45
- opts?: Partial<EcdsaKeypairOptions>,
46
- ): Promise<EcdsaKeypair> {
30
+ privKey: Uint8Array | string,
31
+ opts?: Partial<P256KeypairOptions>,
32
+ ): Promise<P256Keypair> {
47
33
  const { exportable = false } = opts || {}
48
- const keypair = await operations.importKeypairJwk(jwk, exportable)
49
- const pubkeyBuf = await webcrypto.subtle.exportKey('raw', keypair.publicKey)
50
- const pubkeyBytes = new Uint8Array(pubkeyBuf)
51
- return new EcdsaKeypair(keypair, pubkeyBytes, exportable)
34
+ const privKeyBytes =
35
+ typeof privKey === 'string'
36
+ ? uint8arrays.fromString(privKey, 'hex')
37
+ : privKey
38
+ return new P256Keypair(privKeyBytes, exportable)
52
39
  }
53
40
 
54
41
  publicKeyBytes(): Uint8Array {
@@ -64,21 +51,18 @@ export class EcdsaKeypair implements Keypair {
64
51
  }
65
52
 
66
53
  async sign(msg: Uint8Array): Promise<Uint8Array> {
67
- const buf = await webcrypto.subtle.sign(
68
- { name: 'ECDSA', hash: { name: 'SHA-256' } },
69
- this.keypair.privateKey,
70
- msg.buffer,
71
- )
72
- return new Uint8Array(buf)
54
+ const msgHash = await sha256(msg)
55
+ // return raw 64 byte sig not DER-encoded
56
+ const sig = await p256.sign(msgHash, this.privateKey, { lowS: true })
57
+ return sig.toCompactRawBytes()
73
58
  }
74
59
 
75
- async export(): Promise<JsonWebKey> {
60
+ async export(): Promise<Uint8Array> {
76
61
  if (!this.exportable) {
77
62
  throw new Error('Private key is not exportable')
78
63
  }
79
- const jwk = await webcrypto.subtle.exportKey('jwk', this.keypair.privateKey)
80
- return jwk
64
+ return this.privateKey
81
65
  }
82
66
  }
83
67
 
84
- export default EcdsaKeypair
68
+ export default P256Keypair
@@ -1,30 +1,8 @@
1
- import { webcrypto } from 'one-webcrypto'
1
+ import { p256 } from '@noble/curves/p256'
2
+ import { sha256 } from '@noble/hashes/sha256'
2
3
  import { P256_JWT_ALG } from '../const'
3
4
  import { parseDidKey } from '../did'
4
5
 
5
- export const importKeypairJwk = async (
6
- jwk: JsonWebKey,
7
- exportable = false,
8
- ): Promise<CryptoKeyPair> => {
9
- const privateKey = await webcrypto.subtle.importKey(
10
- 'jwk',
11
- jwk,
12
- { name: 'ECDSA', namedCurve: 'P-256' },
13
- exportable,
14
- ['sign'],
15
- )
16
- const { kty, crv, x, y } = jwk
17
- const pubKeyJwk = { kty, crv, x, y }
18
- const publicKey = await webcrypto.subtle.importKey(
19
- 'jwk',
20
- pubKeyJwk,
21
- { name: 'ECDSA', namedCurve: 'P-256' },
22
- true,
23
- ['verify'],
24
- )
25
- return { privateKey, publicKey }
26
- }
27
-
28
6
  export const verifyDidSig = async (
29
7
  did: string,
30
8
  data: Uint8Array,
@@ -34,31 +12,14 @@ export const verifyDidSig = async (
34
12
  if (jwtAlg !== P256_JWT_ALG) {
35
13
  throw new Error(`Not a P-256 did:key: ${did}`)
36
14
  }
37
- return verify(keyBytes, data, sig)
15
+ return verifySig(keyBytes, data, sig)
38
16
  }
39
17
 
40
- export const verify = async (
18
+ export const verifySig = async (
41
19
  publicKey: Uint8Array,
42
20
  data: Uint8Array,
43
21
  sig: Uint8Array,
44
22
  ): Promise<boolean> => {
45
- const importedKey = await importEcdsaPublicKey(publicKey)
46
- return webcrypto.subtle.verify(
47
- { name: 'ECDSA', hash: { name: 'SHA-256' } },
48
- importedKey,
49
- sig,
50
- data,
51
- )
52
- }
53
-
54
- export const importEcdsaPublicKey = async (
55
- keyBytes: Uint8Array,
56
- ): Promise<CryptoKey> => {
57
- return webcrypto.subtle.importKey(
58
- 'raw',
59
- keyBytes,
60
- { name: 'ECDSA', namedCurve: 'P-256' },
61
- true,
62
- ['verify'],
63
- )
23
+ const msgHash = await sha256(data)
24
+ return p256.verify(sig, msgHash, publicKey, { lowS: true })
64
25
  }
package/src/random.ts CHANGED
@@ -1,14 +1,9 @@
1
+ import * as noble from '@noble/hashes/utils'
1
2
  import * as uint8arrays from 'uint8arrays'
2
- import { webcrypto } from 'one-webcrypto'
3
3
  import { SupportedEncodings } from 'uint8arrays/to-string'
4
+ import { sha256 } from './sha'
4
5
 
5
- export const randomBytes = (length: number): Uint8Array => {
6
- return webcrypto.getRandomValues(new Uint8Array(length))
7
- }
8
-
9
- export const randomIV = (): Uint8Array => {
10
- return randomBytes(12)
11
- }
6
+ export const randomBytes = noble.randomBytes
12
7
 
13
8
  export const randomStr = (
14
9
  byteLength: number,
@@ -17,3 +12,15 @@ export const randomStr = (
17
12
  const bytes = randomBytes(byteLength)
18
13
  return uint8arrays.toString(bytes, encoding)
19
14
  }
15
+
16
+ export const randomIntFromSeed = async (
17
+ seed: string,
18
+ high: number,
19
+ low = 0,
20
+ ): Promise<number> => {
21
+ const hash = await sha256(seed)
22
+ const number = Buffer.from(hash).readUintBE(0, 6)
23
+ const range = high - low
24
+ const normalized = number % range
25
+ return normalized + low
26
+ }
@@ -1,8 +1,7 @@
1
- import * as secp from '@noble/secp256k1'
1
+ import { secp256k1 as k256 } from '@noble/curves/secp256k1'
2
2
 
3
3
  export const compressPubkey = (pubkeyBytes: Uint8Array): Uint8Array => {
4
- const hex = secp.utils.bytesToHex(pubkeyBytes)
5
- const point = secp.Point.fromHex(hex)
4
+ const point = k256.ProjectivePoint.fromHex(pubkeyBytes)
6
5
  return point.toRawBytes(true)
7
6
  }
8
7
 
@@ -10,7 +9,6 @@ export const decompressPubkey = (compressed: Uint8Array): Uint8Array => {
10
9
  if (compressed.length !== 33) {
11
10
  throw new Error('Expected 33 byte compress pubkey')
12
11
  }
13
- const hex = secp.utils.bytesToHex(compressed)
14
- const point = secp.Point.fromHex(hex)
12
+ const point = k256.ProjectivePoint.fromHex(compressed)
15
13
  return point.toRawBytes(false)
16
14
  }
@@ -1,4 +1,5 @@
1
- import * as secp from '@noble/secp256k1'
1
+ import { secp256k1 as k256 } from '@noble/curves/secp256k1'
2
+ import { sha256 } from '@noble/hashes/sha256'
2
3
  import * as uint8arrays from 'uint8arrays'
3
4
  import { SupportedEncodings } from 'uint8arrays/util/bases'
4
5
  import * as did from '../did'
@@ -14,14 +15,14 @@ export class Secp256k1Keypair implements Keypair {
14
15
  private publicKey: Uint8Array
15
16
 
16
17
  constructor(private privateKey: Uint8Array, private exportable: boolean) {
17
- this.publicKey = secp.getPublicKey(privateKey)
18
+ this.publicKey = k256.getPublicKey(privateKey)
18
19
  }
19
20
 
20
21
  static async create(
21
22
  opts?: Partial<Secp256k1KeypairOptions>,
22
23
  ): Promise<Secp256k1Keypair> {
23
24
  const { exportable = false } = opts || {}
24
- const privKey = secp.utils.randomPrivateKey()
25
+ const privKey = k256.utils.randomPrivateKey()
25
26
  return new Secp256k1Keypair(privKey, exportable)
26
27
  }
27
28
 
@@ -50,9 +51,10 @@ export class Secp256k1Keypair implements Keypair {
50
51
  }
51
52
 
52
53
  async sign(msg: Uint8Array): Promise<Uint8Array> {
53
- const msgHash = await secp.utils.sha256(msg)
54
+ const msgHash = await sha256(msg)
54
55
  // return raw 64 byte sig not DER-encoded
55
- return secp.sign(msgHash, this.privateKey, { der: false })
56
+ const sig = await k256.sign(msgHash, this.privateKey, { lowS: true })
57
+ return sig.toCompactRawBytes()
56
58
  }
57
59
 
58
60
  async export(): Promise<Uint8Array> {
@@ -1,4 +1,5 @@
1
- import * as secp from '@noble/secp256k1'
1
+ import { secp256k1 as k256 } from '@noble/curves/secp256k1'
2
+ import { sha256 } from '@noble/hashes/sha256'
2
3
  import { SECP256K1_JWT_ALG } from '../const'
3
4
  import { parseDidKey } from '../did'
4
5
 
@@ -11,6 +12,14 @@ export const verifyDidSig = async (
11
12
  if (jwtAlg !== SECP256K1_JWT_ALG) {
12
13
  throw new Error(`Not a secp256k1 did:key: ${did}`)
13
14
  }
14
- const msgHash = await secp.utils.sha256(data)
15
- return secp.verify(sig, msgHash, keyBytes)
15
+ return verifySig(keyBytes, data, sig)
16
+ }
17
+
18
+ export const verifySig = async (
19
+ publicKey: Uint8Array,
20
+ data: Uint8Array,
21
+ sig: Uint8Array,
22
+ ): Promise<boolean> => {
23
+ const msgHash = await sha256(data)
24
+ return k256.verify(sig, msgHash, publicKey, { lowS: true })
16
25
  }
package/src/sha.ts CHANGED
@@ -1,7 +1,5 @@
1
- import * as mf from 'multiformats/hashes/sha2'
1
+ import * as noble from '@noble/hashes/sha256'
2
2
  import * as uint8arrays from 'uint8arrays'
3
- import crypto from 'crypto'
4
- import { Readable } from 'stream'
5
3
 
6
4
  // takes either bytes of utf8 input
7
5
  export const sha256 = async (
@@ -9,20 +7,5 @@ export const sha256 = async (
9
7
  ): Promise<Uint8Array> => {
10
8
  const bytes =
11
9
  typeof input === 'string' ? uint8arrays.fromString(input, 'utf8') : input
12
- const hash = await mf.sha256.digest(bytes)
13
- return hash.digest
14
- }
15
-
16
- export const sha256Stream = async (stream: Readable): Promise<Uint8Array> => {
17
- const hash = crypto.createHash('sha256')
18
- try {
19
- for await (const chunk of stream) {
20
- hash.write(chunk)
21
- }
22
- } catch (err) {
23
- hash.end()
24
- throw err
25
- }
26
- hash.end()
27
- return hash.read()
10
+ return noble.sha256(bytes)
28
11
  }
package/src/types.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export interface Signer {
2
+ jwtAlg: string
2
3
  sign(msg: Uint8Array): Promise<Uint8Array>
3
4
  }
4
5