Skip to content

Commit

Permalink
Rename Point to JPoint
Browse files Browse the repository at this point in the history
  • Loading branch information
paulmillr committed Jan 17, 2023
1 parent b7b6e42 commit 2298b09
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 82 deletions.
3 changes: 2 additions & 1 deletion index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -419,5 +419,6 @@ const wNAF = (n: bigint): { p: Point; f: Point } => { // w-ary non-adjacent fo
}
return { p, f } // return both real and fake points for JIT
}; // !! you can disable precomputes by commenting-out call of the wNAF() inside Point#mul()
export const JPoint = Point;
export const utils = ut;
export { getPublicKey, sign, signSync, verify, getSharedSecret, CURVE, Point, Signature };
export { getPublicKey, sign, signSync, verify, getSharedSecret, CURVE, Signature };
164 changes: 83 additions & 81 deletions test/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const INVALID_ITEMS = ['deadbeef', Math.pow(2, 53), [1], 'xyzxyzxyxyzxyzxyxyzxyz
const toBEHex = (n: number | bigint) => n.toString(16).padStart(64, '0');
const hex = secp.utils.bytesToHex;
const hexToBytes = secp.utils.hexToBytes;
const Point = secp.JPoint;

// const { Signature } = secp;
const { bytesToNumber: b2n, hexToBytes: h2b } = secp.utils;
Expand Down Expand Up @@ -91,15 +92,15 @@ describe('secp256k1', () => {
.filter((line) => line)
.map((line) => line.split(':'));
for (let [priv, x, y] of data) {
const { x: x1, y: y1 } = secp.Point.fromPrivateKey(BigInt(priv)).aff();
const { x: x1, y: y1 } = Point.fromPrivateKey(BigInt(priv)).aff();
expect(toBEHex(x1)).toBe(x);
expect(toBEHex(y1)).toBe(y);

const { x: x2, y: y2 } = secp.Point.fromHex(secp.getPublicKey(toBEHex(BigInt(priv)))).aff();
const { x: x2, y: y2 } = Point.fromHex(secp.getPublicKey(toBEHex(BigInt(priv)))).aff();
expect(toBEHex(x2)).toBe(x);
expect(toBEHex(y2)).toBe(y);

const { x: x3, y: y3 } = secp.Point.fromHex(
const { x: x3, y: y3 } = Point.fromHex(
secp.getPublicKey(hexToBytes(toBEHex(BigInt(priv))))
).aff();
expect(toBEHex(x3)).toBe(x);
Expand Down Expand Up @@ -136,49 +137,49 @@ describe('secp256k1', () => {
for (const vector of points.valid.isPoint) {
const { P, expected } = vector;
if (expected) {
secp.Point.fromHex(P);
Point.fromHex(P);
} else {
expect(() => secp.Point.fromHex(P)).toThrowError();
expect(() => Point.fromHex(P)).toThrowError();
}
}
});

it('.fromPrivateKey()', () => {
for (const vector of points.valid.pointFromScalar) {
const { d, expected } = vector;
let p = secp.Point.fromPrivateKey(d);
let p = Point.fromPrivateKey(d);
expect(p.toHex(true)).toBe(expected);
}
});

it('#toHex(compressed)', () => {
for (const vector of points.valid.pointCompress) {
const { P, compress, expected } = vector;
let p = secp.Point.fromHex(P);
let p = Point.fromHex(P);
expect(p.toHex(compress)).toBe(expected);
}
});

it('#toHex() roundtrip', () => {
fc.assert(
fc.property(FC_BIGINT, (x) => {
const point1 = secp.Point.fromPrivateKey(x);
const point1 = Point.fromPrivateKey(x);
const hex = point1.toHex(true);
expect(secp.Point.fromHex(hex).toHex(true)).toBe(hex);
expect(Point.fromHex(hex).toHex(true)).toBe(hex);
})
);
});

it('#add(other)', () => {
for (const vector of points.valid.pointAdd) {
const { P, Q, expected } = vector;
let p = secp.Point.fromHex(P);
let q = secp.Point.fromHex(Q);
let p = Point.fromHex(P);
let q = Point.fromHex(Q);
if (expected) {
expect(p.add(q).toHex(true)).toBe(expected);
} else {
if (p.eql(q.neg())) {
expect(p.add(q).toHex(true)).toBe(secp.Point.I.toHex(true));
expect(p.add(q).toHex(true)).toBe(Point.I.toHex(true));
} else {
expect(() => p.add(q).toHex(true)).toThrowError();
}
Expand All @@ -189,7 +190,7 @@ describe('secp256k1', () => {
it('#multiply(privateKey)', () => {
for (const vector of points.valid.pointMultiply) {
const { P, d, expected } = vector;
const p = secp.Point.fromHex(P);
const p = Point.fromHex(P);
if (expected) {
expect(p.mul(hexToNumber(d)).toHex(true)).toBe(expected);
} else {
Expand All @@ -203,14 +204,14 @@ describe('secp256k1', () => {
const { P, d } = vector;
if (hexToNumber(d) < secp.CURVE.n) {
expect(() => {
const p = secp.Point.fromHex(P);
const p = Point.fromHex(P);
p.mul(hexToNumber(d)).toHex(true);
}).toThrowError();
}
}
for (const num of [0n, 0, -1n, -1, 1.1]) {
// @ts-ignore
expect(() => secp.Point.BASE.multiply(num)).toThrowError();
expect(() => Point.G.multiply(num)).toThrowError();
}
});

Expand All @@ -237,14 +238,14 @@ describe('secp256k1', () => {
);
});

// it('.fromDERHex() roundtrip', () => {
// fc.assert(
// fc.property(FC_BIGINT, FC_BIGINT, (r, s) => {
// const sig = new secp.Signature(r, s);
// expect(secp.Signature.fromDER(sig.toDERHex())).toEqual(sig);
// })
// );
// });
it('.fromDERHex() roundtrip', () => {
fc.assert(
fc.property(FC_BIGINT, FC_BIGINT, (r, s) => {
const sig = new secp.Signature(r, s);
expect(DER.toSig(DER.hexFromSig(sig))).toEqual(sig);
})
);
});
});

describe('.sign()', () => {
Expand Down Expand Up @@ -273,51 +274,52 @@ describe('secp256k1', () => {
expect(async () => await secp.sign('')).rejects.toThrowError();
});

// it('should create correct DER encoding against libsecp256k1', async () => {
// const CASES = [
// [
// 'd1a9dc8ed4e46a6a3e5e594615ca351d7d7ef44df1e4c94c1802f3592183794b',
// '304402203de2559fccb00c148574997f660e4d6f40605acc71267ee38101abf15ff467af02200950abdf40628fd13f547792ba2fc544681a485f2fdafb5c3b909a4df7350e6b',
// ],
// [
// '5f97983254982546d3976d905c6165033976ee449d300d0e382099fa74deaf82',
// '3045022100c046d9ff0bd2845b9aa9dff9f997ecebb31e52349f80fe5a5a869747d31dcb88022011f72be2a6d48fe716b825e4117747b397783df26914a58139c3f4c5cbb0e66c',
// ],
// [
// '0d7017a96b97cd9be21cf28aada639827b2814a654a478c81945857196187808',
// '3045022100d18990bba7832bb283e3ecf8700b67beb39acc73f4200ed1c331247c46edccc602202e5c8bbfe47ae159512c583b30a3fa86575cddc62527a03de7756517ae4c6c73',
// ],
// ];
// const privKey = hexToBytes(
// '0101010101010101010101010101010101010101010101010101010101010101'
// );
// for (let [msg, exp] of CASES) {
// const res = await secp.sign(msg, privKey, { extraEntropy: undefined });
// expect(hex(res)).toBe(exp);
// const rs = secp.Signature.fromDER(res).toCompactHex();
// expect(secp.Signature.fromCompact(rs).toDERHex()).toBe(exp);
// }
// });
// it('sign ecdsa extraData', async () => {
// const ent1 = '0000000000000000000000000000000000000000000000000000000000000000';
// const ent2 = '0000000000000000000000000000000000000000000000000000000000000001';
// const ent3 = '6e723d3fd94ed5d2b6bdd4f123364b0f3ca52af829988a63f8afe91d29db1c33';
// const ent4 = 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141';
// const ent5 = 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff';

// for (const e of ecdsa.extraEntropy) {
// const sign = async (extraEntropy?: string) => {
// const s = await secp.sign(e.m, e.d, { der: false, extraEntropy });
// return s.toCompactHex();
// };
// expect(await sign()).toBe(e.signature);
// expect(await sign(ent1)).toBe(e.extraEntropy0);
// expect(await sign(ent2)).toBe(e.extraEntropy1);
// expect(await sign(ent3)).toBe(e.extraEntropyRand);
// expect(await sign(ent4)).toBe(e.extraEntropyN);
// expect(await sign(ent5)).toBe(e.extraEntropyMax);
// }
// });
it('should create correct DER encoding against libsecp256k1', async () => {
const CASES = [
[
'd1a9dc8ed4e46a6a3e5e594615ca351d7d7ef44df1e4c94c1802f3592183794b',
'304402203de2559fccb00c148574997f660e4d6f40605acc71267ee38101abf15ff467af02200950abdf40628fd13f547792ba2fc544681a485f2fdafb5c3b909a4df7350e6b',
],
[
'5f97983254982546d3976d905c6165033976ee449d300d0e382099fa74deaf82',
'3045022100c046d9ff0bd2845b9aa9dff9f997ecebb31e52349f80fe5a5a869747d31dcb88022011f72be2a6d48fe716b825e4117747b397783df26914a58139c3f4c5cbb0e66c',
],
[
'0d7017a96b97cd9be21cf28aada639827b2814a654a478c81945857196187808',
'3045022100d18990bba7832bb283e3ecf8700b67beb39acc73f4200ed1c331247c46edccc602202e5c8bbfe47ae159512c583b30a3fa86575cddc62527a03de7756517ae4c6c73',
],
];
const privKey = hexToBytes(
'0101010101010101010101010101010101010101010101010101010101010101'
);
for (let [msg, exp] of CASES) {
const res = await secp.sign(msg, privKey, { extraEntropy: undefined });
const derRes = DER.hexFromSig(res);
expect(derRes).toBe(exp);
const derRes2 = DER.toSig(derRes);
expect(DER.hexFromSig(derRes2)).toBe(exp);
}
});
it('sign ecdsa extraData', async () => {
const ent1 = '0000000000000000000000000000000000000000000000000000000000000000';
const ent2 = '0000000000000000000000000000000000000000000000000000000000000001';
const ent3 = '6e723d3fd94ed5d2b6bdd4f123364b0f3ca52af829988a63f8afe91d29db1c33';
const ent4 = 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141';
const ent5 = 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff';

for (const e of ecdsa.extraEntropy) {
const sign = async (extraEntropy?: string) => {
const s = await secp.sign(e.m, e.d, { extraEntropy });
return s.toCompactHex();
};
expect(await sign()).toBe(e.signature);
expect(await sign(ent1)).toBe(e.extraEntropy0);
expect(await sign(ent2)).toBe(e.extraEntropy1);
expect(await sign(ent3)).toBe(e.extraEntropyRand);
expect(await sign(ent4)).toBe(e.extraEntropyN);
expect(await sign(ent5)).toBe(e.extraEntropyMax);
}
});
});

describe('.verify()', () => {
Expand All @@ -334,7 +336,7 @@ describe('secp256k1', () => {
const PRIV_KEY = secp.utils.numToField(0x2n);
const WRONG_PRIV_KEY = secp.utils.numToField(0x22n);
const signature = await secp.sign(MSG, PRIV_KEY);
const publicKey = secp.Point.fromPrivateKey(WRONG_PRIV_KEY).toHex();
const publicKey = Point.fromPrivateKey(WRONG_PRIV_KEY).toHex();
expect(publicKey.length).toBe(130);
expect(secp.verify(signature, MSG, publicKey)).toBe(false);
});
Expand Down Expand Up @@ -371,7 +373,7 @@ describe('secp256k1', () => {
const r = 1n;
const s = 115792089237316195423570985008687907852837564279074904382605163141518162728904n;

const pub = new secp.Point(x, y);
const pub = new Point(x, y);
const signature = new secp.Signature(2n, 2n);
// @ts-ignore
signature.r = r;
Expand All @@ -388,7 +390,7 @@ describe('secp256k1', () => {
const y = 32670510020758816978083085130507043184471273380659243275938904335757337482424n;
const r = 104546003225722045112039007203142344920046999340768276760147352389092131869133n;
const s = 96900796730960181123786672629079577025401317267213807243199432755332205217369n;
const pub = new secp.Point(x, y).toRawBytes();
const pub = new Point(x, y).toRawBytes();
const sig = new secp.Signature(r, s);
expect(secp.verify(sig, msg, pub)).toBeFalsy();
});
Expand All @@ -398,7 +400,7 @@ describe('secp256k1', () => {
const y = 17482644437196207387910659778872952193236850502325156318830589868678978890912n;
const r = 432420386565659656852420866390673177323n;
const s = 115792089237316195423570985008687907852837564279074904382605163141518161494334n;
const pub = new secp.Point(x, y).toRawBytes();
const pub = new Point(x, y).toRawBytes();
const sig = new secp.Signature(r, s);
expect(secp.verify(sig, msg, pub, { lowS: false })).toBeTruthy();
});
Expand Down Expand Up @@ -446,7 +448,7 @@ describe('secp256k1', () => {
it('should recover public key from recovery bit', async () => {
const message = '00000000000000000000000000000000000000000000000000000000deadbeef';
const privateKey = secp.utils.numToField(123456789n);
const publicKey = secp.Point.fromHex(secp.getPublicKey(privateKey)).toHex(false);
const publicKey = Point.fromHex(secp.getPublicKey(privateKey)).toHex(false);
const sig = await secp.sign(message, privateKey);
const recoveredPubkey = sig.recoverPublicKey(message);
expect(recoveredPubkey).not.toBe(null);
Expand Down Expand Up @@ -544,16 +546,16 @@ describe('secp256k1', () => {
},

pointAddScalar: (p: Hex, tweak: Hex, isCompressed?: boolean): Uint8Array => {
const P = secp.Point.fromHex(p);
const P = Point.fromHex(p);
const t = normal(tweak);
const Q = P.add(secp.Point.G.mul(t));
// const Q = secp.Point.BASE.multiplyAndAddUnsafe(P, t, 1n);
if (!Q || Q.eql(secp.Point.I)) throw new Error('Tweaked point at infinity');
const Q = P.add(Point.G.mul(t));
// const Q = Point.G.multiplyAndAddUnsafe(P, t, 1n);
if (!Q || Q.eql(Point.I)) throw new Error('Tweaked point at infinity');
return Q.toRawBytes(isCompressed);
},

pointMultiply: (p: Hex, tweak: Hex, isCompressed?: boolean): Uint8Array => {
const P = secp.Point.fromHex(p);
const P = Point.fromHex(p);
const h = typeof tweak === 'string' ? tweak : secp.utils.bytesToHex(tweak);
const t = BigInt(`0x${h}`);
return P.mul(t).toRawBytes(isCompressed);
Expand Down Expand Up @@ -605,7 +607,7 @@ describe('secp256k1', () => {
const sha256 = (m: Uint8Array) => Uint8Array.from(createHash('sha256').update(m).digest());
it('should pass all tests', async () => {
for (let group of wp.testGroups) {
const pubKey = secp.Point.fromHex(group.key.uncompressed);
const pubKey = Point.fromHex(group.key.uncompressed);
for (let test of group.tests) {
const m = sha256(hexToBytes(test.msg));
if (test.result === 'valid' || test.result === 'acceptable') {
Expand Down Expand Up @@ -635,8 +637,8 @@ describe('secp256k1', () => {
});

// describe('JacobianPoint', () => {
// const JZERO = secp.utils._JacobianPoint.ZERO;
// const AZERO = secp.utils._JacobianPoint.fromAffine(secp.Point.ZERO);
// const JZERO = Point.I;
// const AZERO = { x: 0n, y: 0n };
// expect(AZERO.equals(JZERO)).toBeTruthy();
// expect(AZERO.toAffine().equals(JZERO.toAffine())).toBeTruthy();
// });

0 comments on commit 2298b09

Please sign in to comment.