@covenance/dlc
Version:
Crypto and Bitcoin functions for Covenance DLC implementation
180 lines (161 loc) • 6.41 kB
text/typescript
import { expect } from 'chai';
import { Point, utils } from '../src/crypto/secp256k1';
import {
hexToBytes,
bytesToHex,
pointToHex,
hexToPoint,
signatureToHex,
hexToSignature,
adaptorSignatureToHex,
hexToAdaptorSignature,
sha256,
sha256Hex,
be32
} from '../src/utils';
import { Signature, AdaptorSignature } from '../src/crypto/types';
describe('Utility Functions', () => {
describe('hexToBytes and bytesToHex', () => {
it('should convert between hex strings and bytes correctly', () => {
const hex = '0123456789abcdef';
const bytes = hexToBytes(hex);
expect(bytesToHex(bytes)).to.equal(hex);
});
it('should handle empty hex string', () => {
const hex = '';
const bytes = hexToBytes(hex);
expect(bytes.length).to.equal(0);
expect(bytesToHex(bytes)).to.equal('');
});
it('should handle zero bytes', () => {
const hex = '00000000';
const bytes = hexToBytes(hex);
expect(bytes.length).to.equal(4);
expect(bytesToHex(bytes)).to.equal(hex);
});
});
describe('pointToHex and hexToPoint', () => {
it('should convert between Points and hex strings correctly', () => {
const point = Point.fromPrivateKey(utils.randomPrivateKey());
const hex = pointToHex(point);
const point2 = hexToPoint(hex);
expect(point2.equals(point)).to.be.true;
});
it('should handle generator point', () => {
const point = Point.BASE;
const hex = pointToHex(point);
const point2 = hexToPoint(hex);
expect(point2.equals(point)).to.be.true;
});
it('should throw error for invalid point hex', () => {
expect(() => hexToPoint('00')).to.throw();
});
});
describe('signatureToHex and hexToSignature', () => {
it('should convert between Signatures and hex strings correctly', () => {
const sig: Signature = {
R: Point.fromPrivateKey(utils.randomPrivateKey()),
s: BigInt('123456789')
};
const hex = signatureToHex(sig);
const sig2 = hexToSignature(hex);
expect(sig2.R.equals(sig.R)).to.be.true;
expect(sig2.s).to.equal(sig.s);
});
it('should handle zero s value', () => {
const sig: Signature = {
R: Point.fromPrivateKey(utils.randomPrivateKey()),
s: BigInt(0)
};
const hex = signatureToHex(sig);
const sig2 = hexToSignature(hex);
expect(sig2.R.equals(sig.R)).to.be.true;
expect(sig2.s).to.equal(sig.s);
});
it('should handle large s values', () => {
const sig: Signature = {
R: Point.fromPrivateKey(utils.randomPrivateKey()),
s: BigInt('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff')
};
const hex = signatureToHex(sig);
const sig2 = hexToSignature(hex);
expect(sig2.R.equals(sig.R)).to.be.true;
expect(sig2.s).to.equal(sig.s);
});
});
describe('adaptorSignatureToHex and hexToAdaptorSignature', () => {
it('should convert between AdaptorSignatures and hex strings correctly', () => {
const sig: AdaptorSignature = {
R_prime: Point.fromPrivateKey(utils.randomPrivateKey()),
s_prime: BigInt('987654321')
};
const hex = adaptorSignatureToHex(sig);
const sig2 = hexToAdaptorSignature(hex);
expect(sig2.R_prime.equals(sig.R_prime)).to.be.true;
expect(sig2.s_prime).to.equal(sig.s_prime);
});
it('should handle zero s_prime value', () => {
const sig: AdaptorSignature = {
R_prime: Point.fromPrivateKey(utils.randomPrivateKey()),
s_prime: BigInt(0)
};
const hex = adaptorSignatureToHex(sig);
const sig2 = hexToAdaptorSignature(hex);
expect(sig2.R_prime.equals(sig.R_prime)).to.be.true;
expect(sig2.s_prime).to.equal(sig.s_prime);
});
it('should handle large s_prime values', () => {
const sig: AdaptorSignature = {
R_prime: Point.fromPrivateKey(utils.randomPrivateKey()),
s_prime: BigInt('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff')
};
const hex = adaptorSignatureToHex(sig);
const sig2 = hexToAdaptorSignature(hex);
expect(sig2.R_prime.equals(sig.R_prime)).to.be.true;
expect(sig2.s_prime).to.equal(sig.s_prime);
});
});
describe('sha256 and sha256Hex', () => {
it('should compute correct SHA256 hash', async () => {
const message = new Uint8Array([1, 2, 3, 4, 5]);
const hash = await sha256(message);
expect(hash).to.be.instanceOf(Uint8Array);
expect(hash.length).to.equal(32);
});
it('should compute correct SHA256 hash from hex string', async () => {
const hex = '0102030405';
const hash = await sha256Hex(hex);
expect(hash).to.be.a('string');
expect(hash.length).to.equal(64);
});
});
describe('be32', () => {
it('should write a typical number correctly', () => {
const arr = new Uint8Array(32);
be32(arr, 0, BigInt('0x1234567890abcdef'));
expect(bytesToHex(arr)).to.equal('0000000000000000000000000000000000000000000000001234567890abcdef');
});
it('should handle offset correctly', () => {
const arr = new Uint8Array(64);
be32(arr, 32, BigInt('0x1234567890abcdef'));
expect(bytesToHex(arr.slice(0, 32))).to.equal('0000000000000000000000000000000000000000000000000000000000000000');
expect(bytesToHex(arr.slice(32))).to.equal('0000000000000000000000000000000000000000000000001234567890abcdef');
});
it('should handle zero correctly', () => {
const arr = new Uint8Array(32);
be32(arr, 0, BigInt(0));
expect(bytesToHex(arr)).to.equal('0000000000000000000000000000000000000000000000000000000000000000');
});
it('should handle maximum 256-bit number', () => {
const arr = new Uint8Array(32);
const maxValue = BigInt('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff');
be32(arr, 0, maxValue);
expect(bytesToHex(arr)).to.equal('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff');
});
it('should throw error for number larger than 256 bits', () => {
const arr = new Uint8Array(32);
const tooLarge = BigInt('0x10000000000000000000000000000000000000000000000000000000000000000');
expect(() => be32(arr, 0, tooLarge)).to.throw(RangeError, 'integer > 256 bits');
});
});
});