Skip to content

Commit 42aad3d

Browse files
authored
add recovery bit to allow restoring the public key (#137)
1 parent 86d9676 commit 42aad3d

File tree

7 files changed

+48
-35
lines changed

7 files changed

+48
-35
lines changed

packages/hypergraph/src/space-events/accept-invitation.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,18 @@ export const acceptInvitation = ({
1919
previousEventHash,
2020
};
2121
const encodedTransaction = stringToUint8Array(canonicalize(transaction));
22-
const signature = secp256k1
23-
.sign(encodedTransaction, hexToBytes(author.signaturePrivateKey), { prehash: true })
24-
.toCompactHex();
22+
const signatureResult = secp256k1.sign(encodedTransaction, hexToBytes(author.signaturePrivateKey), {
23+
prehash: true,
24+
});
2525

2626
return Effect.succeed({
2727
transaction,
2828
author: {
2929
accountId: author.accountId,
30-
publicKey: author.signaturePublicKey,
31-
signature,
30+
signature: {
31+
hex: signatureResult.toCompactHex(),
32+
recovery: signatureResult.recovery,
33+
},
3234
},
3335
});
3436
};

packages/hypergraph/src/space-events/apply-event.ts

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { secp256k1 } from '@noble/curves/secp256k1';
2+
import { sha256 } from '@noble/hashes/sha256';
23
import { Effect, Schema } from 'effect';
34
import type { ParseError } from 'effect/ParseResult';
4-
5-
import { canonicalize, hexToBytes, stringToUint8Array } from '../utils/index.js';
5+
import { canonicalize, stringToUint8Array } from '../utils/index.js';
66
import { hashEvent } from './hash-event.js';
77
import {
88
InvalidEventError,
@@ -41,16 +41,15 @@ export const applyEvent = ({
4141

4242
const encodedTransaction = stringToUint8Array(canonicalize(event.transaction));
4343

44-
const isValidSignature = secp256k1.verify(
45-
event.author.signature,
46-
encodedTransaction,
47-
hexToBytes(event.author.publicKey),
48-
{
49-
prehash: true,
50-
},
51-
);
44+
let signatureInstance = secp256k1.Signature.fromCompact(event.author.signature.hex);
45+
signatureInstance = signatureInstance.addRecoveryBit(event.author.signature.recovery);
46+
// @ts-expect-error
47+
const authorPublicKey = signatureInstance.recoverPublicKey(sha256(encodedTransaction));
48+
// TODO compare it to the public key from the author accountId (this already verifies the signature)
49+
// in case of a failure we return Effect.fail(new VerifySignatureError());
5250

53-
if (!isValidSignature) {
51+
// biome-ignore lint/correctness/noConstantCondition: wip
52+
if (false) {
5453
return Effect.fail(new VerifySignatureError());
5554
}
5655

packages/hypergraph/src/space-events/create-invitation.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,18 @@ export const createInvitation = ({
2424
previousEventHash,
2525
};
2626
const encodedTransaction = stringToUint8Array(canonicalize(transaction));
27-
const signature = secp256k1
28-
.sign(encodedTransaction, hexToBytes(author.signaturePrivateKey), { prehash: true })
29-
.toCompactHex();
27+
const signatureResult = secp256k1.sign(encodedTransaction, hexToBytes(author.signaturePrivateKey), {
28+
prehash: true,
29+
});
3030

3131
return Effect.succeed({
3232
transaction,
3333
author: {
3434
accountId: author.accountId,
35-
publicKey: author.signaturePublicKey,
36-
signature,
35+
signature: {
36+
hex: signatureResult.toCompactHex(),
37+
recovery: signatureResult.recovery,
38+
},
3739
},
3840
});
3941
};

packages/hypergraph/src/space-events/create-space.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,18 @@ export const createSpace = ({ author }: Params): Effect.Effect<CreateSpaceEvent,
1515
creatorAccountId: author.accountId,
1616
};
1717
const encodedTransaction = stringToUint8Array(canonicalize(transaction));
18-
const signature = secp256k1
19-
.sign(encodedTransaction, hexToBytes(author.signaturePrivateKey), { prehash: true })
20-
.toCompactHex();
18+
const signatureResult = secp256k1.sign(encodedTransaction, hexToBytes(author.signaturePrivateKey), {
19+
prehash: true,
20+
});
2121

2222
const event: CreateSpaceEvent = {
2323
transaction,
2424
author: {
2525
accountId: author.accountId,
26-
publicKey: author.signaturePublicKey,
27-
signature,
26+
signature: {
27+
hex: signatureResult.toCompactHex(),
28+
recovery: signatureResult.recovery,
29+
},
2830
},
2931
};
3032

packages/hypergraph/src/space-events/delete-space.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,18 @@ export const deleteSpace = ({ author, id, previousEventHash }: Params): Effect.E
1818
previousEventHash,
1919
};
2020
const encodedTransaction = stringToUint8Array(canonicalize(transaction));
21-
const signature = secp256k1
22-
.sign(encodedTransaction, hexToBytes(author.signaturePrivateKey), { prehash: true })
23-
.toCompactHex();
21+
const signatureResult = secp256k1.sign(encodedTransaction, hexToBytes(author.signaturePrivateKey), {
22+
prehash: true,
23+
});
2424

2525
const event: DeleteSpaceEvent = {
2626
transaction,
2727
author: {
2828
accountId: author.accountId,
29-
publicKey: author.signaturePublicKey,
30-
signature,
29+
signature: {
30+
hex: signatureResult.toCompactHex(),
31+
recovery: signatureResult.recovery,
32+
},
3133
},
3234
};
3335
return Effect.succeed(event);

packages/hypergraph/src/space-events/types.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
import * as Schema from 'effect/Schema';
2+
import { SignatureWithRecovery } from '../types.js';
23

34
export const EventAuthor = Schema.Struct({
45
accountId: Schema.String,
5-
// must be validated if it belongs to the accountId before being used
6-
// Note: could be removed, but also might be useful to keep around in case accounts rotate their keys
7-
publicKey: Schema.String,
8-
signature: Schema.String,
6+
signature: SignatureWithRecovery,
97
});
108

119
export type EventAuthor = Schema.Schema.Type<typeof Author>;

packages/hypergraph/src/types.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import * as Schema from 'effect/Schema';
2+
3+
export const SignatureWithRecovery = Schema.Struct({
4+
hex: Schema.String,
5+
recovery: Schema.Number,
6+
});
7+
8+
export type SignatureWithRecovery = Schema.Schema.Type<typeof SignatureWithRecovery>;

0 commit comments

Comments
 (0)