UNPKG

o1js

Version:

TypeScript framework for zk-SNARKs and zkApps

1,487 lines (1,306 loc) 86.6 kB
import { Provable, Int64, UInt64, UInt32, UInt8, Field, Bool, Sign, } from 'o1js'; describe('int', () => { const NUMBERMAX = 2 ** 53 - 1; // JavaScript numbers can only safely store integers in the range -(2^53 − 1) to 2^53 − 1 describe('Int64', () => { describe('toString', () => { it('should be the same as Field(0)', async () => { const int = new Int64(UInt64.zero, Sign.one); const field = Field(0); expect(int.toString()).toEqual(field.toString()); }); it('should be -1', async () => { const int = new Int64(UInt64.one).neg(); expect(int.toString()).toEqual('-1'); }); it('should be the same as 2^53-1', async () => { const int = Int64.fromField(Field(String(NUMBERMAX))); const field = Field(String(NUMBERMAX)); expect(int.toString()).toEqual(field.toString()); }); }); describe('zero', () => { it('should be the same as Field(0)', async () => { expect(Int64.zero.magnitude.value).toEqual(Field(0)); }); }); describe('fromUnsigned', () => { it('should be the same as UInt64.zero', async () => { expect(new Int64(UInt64.zero, Sign.one)).toEqual( Int64.fromUnsigned(UInt64.zero) ); }); it('should be the same as UInt64.MAXINT', async () => { expect(Int64.from((1n << 64n) - 1n)).toEqual( Int64.fromUnsigned(UInt64.MAXINT()) ); }); }); describe('neg', () => { it('neg(1)=-1', () => { const int = Int64.one; expect(int.neg().toField()).toEqual(Field(-1)); }); it('neg(2^53-1)=-2^53-1', () => { const int = Int64.from(NUMBERMAX); expect(int.neg().toString()).toEqual(`${-NUMBERMAX}`); }); }); describe('add', () => { it('1+1=2', () => { expect(Int64.one.add(Int64.from('1')).toString()).toEqual('2'); }); it('5000+(-4000)=1000', () => { expect( Int64.from(5000) .add(Int64.fromField(Field(-4000))) .toString() ).toEqual('1000'); }); it('(MAXINT/2+MAXINT/2) adds to MAXINT', () => { const value = ((1n << 64n) - 2n) / 2n; expect( Int64.from(value).add(Int64.from(value)).add(Int64.one).toString() ).toEqual(UInt64.MAXINT().toString()); }); it('should throw on overflow', () => { expect(() => { Int64.from(1n << 64n); }).toThrow(); expect(() => { Int64.from(-(1n << 64n)); }).toThrow(); expect(() => { Int64.from(100).add(1n << 64n); }).toThrow(); expect(() => { Int64.from(100).sub('1180591620717411303424'); }).toThrow(); expect(() => { Int64.from(100).mul(UInt64.from(1n << 100n)); }).toThrow(); }); // TODO - should we make these throw? // These are edge cases, where one of two inputs is out of the Int64 range, // but the result of an operation with a proper Int64 moves it into the range. // They would only get caught if we'd also check the range in the Int64 / UInt64 constructors, // which breaks out current practice of having a dumb constructor that only stores variables it.skip('operations should throw on overflow of any input', () => { expect(() => { new Int64(new UInt64(1n << 64n)).sub(1); }).toThrow(); expect(() => { new Int64(new UInt64(-(1n << 64n))).add(5); }).toThrow(); expect(() => { Int64.from(20).sub(new UInt64((1n << 64n) + 10n)); }).toThrow(); expect(() => { Int64.from(6).add(new UInt64(-(1n << 64n) - 5n)); }).toThrow(); }); it('should throw on overflow addition', () => { expect(() => { Int64.from((1n << 64n) - 1n).add(1); }).toThrow(); expect(() => { Int64.one.add((1n << 64n) - 1n); }).toThrow(); }); it('should not throw on non-overflowing addition', () => { expect(() => { Int64.from((1n << 64n) - 1n).add(Int64.zero); }).not.toThrow(); }); }); describe('sub', () => { it('1-1=0', () => { expect(Int64.one.sub(Int64.from(1)).toString()).toEqual('0'); }); it('10000-5000=5000', () => { expect( Int64.fromField(Field(10000)).sub(Int64.from('5000')).toString() ).toEqual('5000'); }); it('0-1=-1', () => { expect(Int64.zero.sub(Int64.one).toString()).toEqual('-1'); }); it('(0-MAXINT) subs to -MAXINT', () => { expect(Int64.zero.sub(UInt64.MAXINT()).toString()).toEqual( '-' + UInt64.MAXINT().toString() ); }); }); describe('toFields', () => { it('toFields(1) should be the same as [Field(1), Field(1)]', () => { expect(Int64.toFields(Int64.one)).toEqual([Field(1), Field(1)]); }); it('toFields(2^53-1) should be the same as Field(2^53-1)', () => { expect(Int64.toFields(Int64.from(NUMBERMAX))).toEqual([ Field(String(NUMBERMAX)), Field(1), ]); }); }); describe('fromFields', () => { it('fromFields([1, 1]) should be the same as Int64.one', () => { expect(Int64.fromFields([Field(1), Field(1)])).toEqual(Int64.one); }); it('fromFields(2^53-1) should be the same as Field(2^53-1)', () => { expect(Int64.fromFields([Field(String(NUMBERMAX)), Field(1)])).toEqual( Int64.from(NUMBERMAX) ); }); }); describe('mul / div / mod', () => { it('mul, div and mod work', () => { // 2 ** 6 === 64 let x = Int64.fromField(Field(2)) .mul(2) .mul('2') .mul(2n) .mul(UInt32.from(2)) .mul(UInt64.from(2)); expect(`${x}`).toBe('64'); // 64 * (-64) === -64**2 let y = Int64.from(-64); expect(`${x.mul(y)}`).toEqual(`${-(64 ** 2)}`); // (-64) // 64 === -1 expect(y.div(x).toString()).toEqual('-1'); // (-64) // 65 === 0 expect(y.div(65).toString()).toEqual('0'); // 64 % 3 === 1 expect(x.mod(3).toString()).toEqual('1'); // (-64) % 3 === 2 expect(y.mod(3).toString()).toEqual('2'); }); }); }); describe('UInt64', () => { describe('Inside circuit', () => { describe('add', () => { it('1+1=2', async () => { await Provable.runAndCheck(() => { const x = Provable.witness(UInt64, () => new UInt64(1)); const y = Provable.witness(UInt64, () => new UInt64(1)); x.add(y).assertEquals(new UInt64(2)); }); }); it('5000+5000=10000', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt64, () => new UInt64(5000)); const y = Provable.witness(UInt64, () => new UInt64(5000)); x.add(y).assertEquals(new UInt64(10000)); }); }); it('(MAXINT/2+MAXINT/2) adds to MAXINT', async () => { const n = ((1n << 64n) - 2n) / 2n; await Provable.runAndCheck(async () => { const x = Provable.witness(UInt64, () => new UInt64(n)); const y = Provable.witness(UInt64, () => new UInt64(n)); x.add(y).add(1).assertEquals(UInt64.MAXINT()); }); }); it('should throw on overflow addition', async () => { await expect( Provable.runAndCheck(() => { const x = Provable.witness(UInt64, () => UInt64.MAXINT()); const y = Provable.witness(UInt64, () => new UInt64(1)); x.add(y); }) ).rejects.toThrow(); }); }); describe('sub', () => { it('1-1=0', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt64, () => new UInt64(1)); const y = Provable.witness(UInt64, () => new UInt64(1)); x.sub(y).assertEquals(new UInt64(0)); }); }); it('10000-5000=5000', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt64, () => new UInt64(10000)); const y = Provable.witness(UInt64, () => new UInt64(5000)); x.sub(y).assertEquals(new UInt64(5000)); }); }); it('should throw on sub if results in negative number', async () => { await expect( Provable.runAndCheck(async () => { const x = Provable.witness(UInt64, () => new UInt64(0)); const y = Provable.witness(UInt64, () => new UInt64(1)); x.sub(y); }) ).rejects.toThrow(); }); }); describe('mul', () => { it('1x2=2', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt64, () => new UInt64(1)); const y = Provable.witness(UInt64, () => new UInt64(2)); x.mul(y).assertEquals(new UInt64(2)); }); }); it('1x0=0', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt64, () => new UInt64(1)); const y = Provable.witness(UInt64, () => new UInt64(0)); x.mul(y).assertEquals(new UInt64(0)); }); }); it('1000x1000=1000000', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt64, () => new UInt64(1000)); const y = Provable.witness(UInt64, () => new UInt64(1000)); x.mul(y).assertEquals(new UInt64(1000000)); }); }); it('MAXINTx1=MAXINT', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt64, () => UInt64.MAXINT()); const y = Provable.witness(UInt64, () => new UInt64(1)); x.mul(y).assertEquals(UInt64.MAXINT()); }); }); it('should throw on overflow multiplication', async () => { await expect( Provable.runAndCheck(async () => { const x = Provable.witness(UInt64, () => UInt64.MAXINT()); const y = Provable.witness(UInt64, () => new UInt64(2)); x.mul(y); }) ).rejects.toThrow(); }); }); describe('div', () => { it('2/1=2', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt64, () => new UInt64(2)); const y = Provable.witness(UInt64, () => new UInt64(1)); x.div(y).assertEquals(new UInt64(2)); }); }); it('0/1=0', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt64, () => new UInt64(0)); const y = Provable.witness(UInt64, () => new UInt64(1)); x.div(y).assertEquals(new UInt64(0)); }); }); it('2000/1000=2', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt64, () => new UInt64(2000)); const y = Provable.witness(UInt64, () => new UInt64(1000)); x.div(y).assertEquals(new UInt64(2)); }); }); it('MAXINT/1=MAXINT', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt64, () => UInt64.MAXINT()); const y = Provable.witness(UInt64, () => new UInt64(1)); x.div(y).assertEquals(UInt64.MAXINT()); }); }); it('should throw on division by zero', async () => { await expect( Provable.runAndCheck(async () => { const x = Provable.witness(UInt64, () => UInt64.MAXINT()); const y = Provable.witness(UInt64, () => new UInt64(0)); x.div(y); }) ).rejects.toThrow(); }); }); describe('mod', () => { it('1%1=0', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt64, () => new UInt64(1)); const y = Provable.witness(UInt64, () => new UInt64(1)); x.mod(y).assertEquals(new UInt64(0)); }); }); it('500%32=20', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt64, () => new UInt64(500)); const y = Provable.witness(UInt64, () => new UInt64(32)); x.mod(y).assertEquals(new UInt64(20)); }); }); it('MAXINT%7=1', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt64, () => UInt64.MAXINT()); const y = Provable.witness(UInt64, () => new UInt64(7)); x.mod(y).assertEquals(new UInt64(1)); }); }); it('should throw on mod by zero', async () => { await expect( Provable.runAndCheck(async () => { const x = Provable.witness(UInt64, () => UInt64.MAXINT()); const y = Provable.witness(UInt64, () => new UInt64(0)); x.mod(y).assertEquals(new UInt64(1)); }) ).rejects.toThrow(); }); }); describe('assertLt', () => { it('1<2=true', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt64, () => new UInt64(1)); const y = Provable.witness(UInt64, () => new UInt64(2)); x.assertLessThan(y); }); }); it('1<1=false', async () => { await expect( Provable.runAndCheck(async () => { const x = Provable.witness(UInt64, () => new UInt64(1)); const y = Provable.witness(UInt64, () => new UInt64(1)); x.assertLessThan(y); }) ).rejects.toThrow(); }); it('2<1=false', async () => { await expect( Provable.runAndCheck(async () => { const x = Provable.witness(UInt64, () => new UInt64(2)); const y = Provable.witness(UInt64, () => new UInt64(1)); x.assertLessThan(y); }) ).rejects.toThrow(); }); it('1000<100000=true', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt64, () => new UInt64(1000)); const y = Provable.witness(UInt64, () => new UInt64(100000)); x.assertLessThan(y); }); }); it('100000<1000=false', async () => { await expect( Provable.runAndCheck(async () => { const x = Provable.witness(UInt64, () => new UInt64(100000)); const y = Provable.witness(UInt64, () => new UInt64(1000)); x.assertLessThan(y); }) ).rejects.toThrow(); }); it('MAXINT<MAXINT=false', async () => { await expect( Provable.runAndCheck(async () => { const x = Provable.witness(UInt64, () => UInt64.MAXINT()); const y = Provable.witness(UInt64, () => UInt64.MAXINT()); x.assertLessThan(y); }) ).rejects.toThrow(); }); }); describe('assertLte', () => { it('1<=1=true', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt64, () => new UInt64(1)); const y = Provable.witness(UInt64, () => new UInt64(1)); x.assertLessThanOrEqual(y); }); }); it('2<=1=false', async () => { await expect( Provable.runAndCheck(async () => { const x = Provable.witness(UInt64, () => new UInt64(2)); const y = Provable.witness(UInt64, () => new UInt64(1)); x.assertLessThanOrEqual(y); }) ).rejects.toThrow(); }); it('1000<=100000=true', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt64, () => new UInt64(1000)); const y = Provable.witness(UInt64, () => new UInt64(100000)); x.assertLessThanOrEqual(y); }); }); it('100000<=1000=false', async () => { await expect( Provable.runAndCheck(async () => { const x = Provable.witness(UInt64, () => new UInt64(100000)); const y = Provable.witness(UInt64, () => new UInt64(1000)); x.assertLessThanOrEqual(y); }) ).rejects.toThrow(); }); it('MAXINT<=MAXINT=true', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt64, () => UInt64.MAXINT()); const y = Provable.witness(UInt64, () => UInt64.MAXINT()); x.assertLessThanOrEqual(y); }); }); }); describe('assertGreaterThan', () => { it('2>1=true', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt64, () => new UInt64(2)); const y = Provable.witness(UInt64, () => new UInt64(1)); x.assertGreaterThan(y); }); }); it('1>1=false', async () => { await expect( Provable.runAndCheck(async () => { const x = Provable.witness(UInt64, () => new UInt64(1)); const y = Provable.witness(UInt64, () => new UInt64(1)); x.assertGreaterThan(y); }) ).rejects.toThrow(); }); it('1>2=false', async () => { await expect( Provable.runAndCheck(async () => { const x = Provable.witness(UInt64, () => new UInt64(1)); const y = Provable.witness(UInt64, () => new UInt64(2)); x.assertGreaterThan(y); }) ).rejects.toThrow(); }); it('100000>1000=true', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt64, () => new UInt64(100000)); const y = Provable.witness(UInt64, () => new UInt64(1000)); x.assertGreaterThan(y); }); }); it('1000>100000=false', async () => { await expect( Provable.runAndCheck(async () => { const x = Provable.witness(UInt64, () => new UInt64(1000)); const y = Provable.witness(UInt64, () => new UInt64(100000)); x.assertGreaterThan(y); }) ).rejects.toThrow(); }); it('MAXINT>MAXINT=false', async () => { await expect( Provable.runAndCheck(async () => { const x = Provable.witness(UInt64, () => UInt64.MAXINT()); const y = Provable.witness(UInt64, () => UInt64.MAXINT()); x.assertGreaterThan(y); }) ).rejects.toThrow(); }); }); describe('assertGreaterThanOrEqual', () => { it('1<=1=true', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt64, () => new UInt64(1)); const y = Provable.witness(UInt64, () => new UInt64(1)); x.assertGreaterThanOrEqual(y); }); }); it('1>=2=false', async () => { await expect( Provable.runAndCheck(async () => { const x = Provable.witness(UInt64, () => new UInt64(1)); const y = Provable.witness(UInt64, () => new UInt64(2)); x.assertGreaterThanOrEqual(y); }) ).rejects.toThrow(); }); it('100000>=1000=true', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt64, () => new UInt64(100000)); const y = Provable.witness(UInt64, () => new UInt64(1000)); x.assertGreaterThanOrEqual(y); }); }); it('1000>=100000=false', async () => { await expect( Provable.runAndCheck(async () => { const x = Provable.witness(UInt64, () => new UInt64(1000)); const y = Provable.witness(UInt64, () => new UInt64(100000)); x.assertGreaterThanOrEqual(y); }) ).rejects.toThrow(); }); it('MAXINT>=MAXINT=true', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt64, () => UInt64.MAXINT()); const y = Provable.witness(UInt64, () => UInt64.MAXINT()); x.assertGreaterThanOrEqual(y); }); }); }); describe('from() ', () => { describe('fromNumber()', () => { it('should be the same as Field(1)', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt64, () => UInt64.from(1)); const y = Provable.witness(UInt64, () => new UInt64(1)); x.assertEquals(y); }); }); it('should be the same as 2^53-1', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt64, () => UInt64.from(NUMBERMAX)); const y = Provable.witness( UInt64, () => new UInt64(String(NUMBERMAX)) ); x.assertEquals(y); }); }); }); describe('fromString()', () => { it('should be the same as Field(1)', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt64, () => UInt64.from('1')); const y = Provable.witness(UInt64, () => new UInt64(1)); x.assertEquals(y); }); }); it('should be the same as 2^53-1', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt64, () => UInt64.from(String(NUMBERMAX)) ); const y = Provable.witness( UInt64, () => new UInt64(String(NUMBERMAX)) ); x.assertEquals(y); }); }); }); }); }); describe('Outside of circuit', () => { describe('add', () => { it('1+1=2', () => { expect(new UInt64(1).add(1).toString()).toEqual('2'); }); it('5000+5000=10000', () => { expect(new UInt64(5000).add(5000).toString()).toEqual('10000'); }); it('(MAXINT/2+MAXINT/2) adds to MAXINT', () => { const value = ((1n << 64n) - 2n) / 2n; expect( new UInt64(value) .add(new UInt64(value)) .add(new UInt64(1)) .toString() ).toEqual(UInt64.MAXINT().toString()); }); it('should throw on overflow addition', () => { expect(() => { UInt64.MAXINT().add(1); }).toThrow(); }); }); describe('sub', () => { it('1-1=0', () => { expect(new UInt64(1).sub(1).toString()).toEqual('0'); }); it('10000-5000=5000', () => { expect(new UInt64(10000).sub(5000).toString()).toEqual('5000'); }); it('should throw on sub if results in negative number', () => { expect(() => { UInt64.from(0).sub(1); }).toThrow(); }); }); describe('mul', () => { it('1x2=2', () => { expect(new UInt64(1).mul(2).toString()).toEqual('2'); }); it('1x0=0', () => { expect(new UInt64(1).mul(0).toString()).toEqual('0'); }); it('1000x1000=1000000', () => { expect(new UInt64(1000).mul(1000).toString()).toEqual('1000000'); }); it('MAXINTx1=MAXINT', () => { expect(UInt64.MAXINT().mul(1).toString()).toEqual( UInt64.MAXINT().toString() ); }); it('should throw on overflow multiplication', () => { expect(() => { UInt64.MAXINT().mul(2); }).toThrow(); }); }); describe('div', () => { it('2/1=2', () => { expect(new UInt64(2).div(1).toString()).toEqual('2'); }); it('0/1=0', () => { expect(new UInt64(0).div(1).toString()).toEqual('0'); }); it('2000/1000=2', () => { expect(new UInt64(2000).div(1000).toString()).toEqual('2'); }); it('MAXINT/1=MAXINT', () => { expect(UInt64.MAXINT().div(1).toString()).toEqual( UInt64.MAXINT().toString() ); }); it('should throw on division by zero', () => { expect(() => { UInt64.MAXINT().div(0); }).toThrow(); }); }); describe('mod', () => { it('1%1=0', () => { expect(new UInt64(1).mod(1).toString()).toEqual('0'); }); it('500%32=20', () => { expect(new UInt64(500).mod(32).toString()).toEqual('20'); }); it('MAXINT%7=1', () => { expect(UInt64.MAXINT().mod(7).toString()).toEqual('1'); }); it('should throw on mod by zero', () => { expect(() => { UInt64.MAXINT().mod(0); }).toThrow(); }); }); describe('lt', () => { it('1<2=true', () => { expect(new UInt64(1).lessThan(new UInt64(2))).toEqual(Bool(true)); }); it('1<1=false', () => { expect(new UInt64(1).lessThan(new UInt64(1))).toEqual(Bool(false)); }); it('2<1=false', () => { expect(new UInt64(2).lessThan(new UInt64(1))).toEqual(Bool(false)); }); it('1000<100000=true', () => { expect(new UInt64(1000).lessThan(new UInt64(100000))).toEqual( Bool(true) ); }); it('100000<1000=false', () => { expect(new UInt64(100000).lessThan(new UInt64(1000))).toEqual( Bool(false) ); }); it('MAXINT<MAXINT=false', () => { expect(UInt64.MAXINT().lessThan(UInt64.MAXINT())).toEqual( Bool(false) ); }); }); describe('lte', () => { it('1<=1=true', () => { expect(new UInt64(1).lessThanOrEqual(new UInt64(1))).toEqual( Bool(true) ); }); it('2<=1=false', () => { expect(new UInt64(2).lessThanOrEqual(new UInt64(1))).toEqual( Bool(false) ); }); it('1000<=100000=true', () => { expect(new UInt64(1000).lessThanOrEqual(new UInt64(100000))).toEqual( Bool(true) ); }); it('100000<=1000=false', () => { expect(new UInt64(100000).lessThanOrEqual(new UInt64(1000))).toEqual( Bool(false) ); }); it('MAXINT<=MAXINT=true', () => { expect(UInt64.MAXINT().lessThanOrEqual(UInt64.MAXINT())).toEqual( Bool(true) ); }); }); describe('assertLessThanOrEqual', () => { it('1<=1=true', () => { expect(() => { new UInt64(1).assertLessThanOrEqual(new UInt64(1)); }).not.toThrow(); }); it('2<=1=false', () => { expect(() => { new UInt64(2).assertLessThanOrEqual(new UInt64(1)); }).toThrow(); }); it('1000<=100000=true', () => { expect(() => { new UInt64(1000).assertLessThanOrEqual(new UInt64(100000)); }).not.toThrow(); }); it('100000<=1000=false', () => { expect(() => { new UInt64(100000).assertLessThanOrEqual(new UInt64(1000)); }).toThrow(); }); it('MAXINT<=MAXINT=true', () => { expect(() => { UInt64.MAXINT().assertLessThanOrEqual(UInt64.MAXINT()); }).not.toThrow(); }); }); describe('greaterThan', () => { it('2>1=true', () => { expect(new UInt64(2).greaterThan(new UInt64(1))).toEqual(Bool(true)); }); it('1>1=false', () => { expect(new UInt64(1).greaterThan(new UInt64(1))).toEqual(Bool(false)); }); it('1>2=false', () => { expect(new UInt64(1).greaterThan(new UInt64(2))).toEqual(Bool(false)); }); it('100000>1000=true', () => { expect(new UInt64(100000).greaterThan(new UInt64(1000))).toEqual( Bool(true) ); }); it('1000>100000=false', () => { expect(new UInt64(1000).greaterThan(new UInt64(100000))).toEqual( Bool(false) ); }); it('MAXINT>MAXINT=false', () => { expect(UInt64.MAXINT().greaterThan(UInt64.MAXINT())).toEqual( Bool(false) ); }); }); describe('greaterThanOrEqual', () => { it('2>=1=true', () => { expect(new UInt64(2).greaterThanOrEqual(new UInt64(1))).toEqual( Bool(true) ); }); it('1>=1=true', () => { expect(new UInt64(1).greaterThanOrEqual(new UInt64(1))).toEqual( Bool(true) ); }); it('1>=2=false', () => { expect(new UInt64(1).greaterThanOrEqual(new UInt64(2))).toEqual( Bool(false) ); }); it('100000>=1000=true', () => { expect( new UInt64(100000).greaterThanOrEqual(new UInt64(1000)) ).toEqual(Bool(true)); }); it('1000>=100000=false', () => { expect( new UInt64(1000).greaterThanOrEqual(new UInt64(100000)) ).toEqual(Bool(false)); }); it('MAXINT>=MAXINT=true', () => { expect(UInt64.MAXINT().greaterThanOrEqual(UInt64.MAXINT())).toEqual( Bool(true) ); }); }); describe('assertGreaterThan', () => { it('1>1=false', () => { expect(() => { new UInt64(1).assertGreaterThan(new UInt64(1)); }).toThrow(); }); it('2>1=true', () => { expect(() => { new UInt64(2).assertGreaterThan(new UInt64(1)); }).not.toThrow(); }); it('1000>100000=false', () => { expect(() => { new UInt64(1000).assertGreaterThan(new UInt64(100000)); }).toThrow(); }); it('100000>1000=true', () => { expect(() => { new UInt64(100000).assertGreaterThan(new UInt64(1000)); }).not.toThrow(); }); it('MAXINT>MAXINT=false', () => { expect(() => { UInt64.MAXINT().assertGreaterThan(UInt64.MAXINT()); }).toThrow(); }); }); describe('assertGreaterThanOrEqual', () => { it('1>=1=true', () => { expect(() => { new UInt64(1).assertGreaterThanOrEqual(new UInt64(1)); }).not.toThrow(); }); it('2>=1=true', () => { expect(() => { new UInt64(2).assertGreaterThanOrEqual(new UInt64(1)); }).not.toThrow(); }); it('1000>=100000=false', () => { expect(() => { new UInt64(1000).assertGreaterThanOrEqual(new UInt64(100000)); }).toThrow(); }); it('100000>=1000=true', () => { expect(() => { new UInt64(100000).assertGreaterThanOrEqual(new UInt64(1000)); }).not.toThrow(); }); it('MAXINT>=MAXINT=true', () => { expect(() => { UInt64.MAXINT().assertGreaterThanOrEqual(UInt64.MAXINT()); }).not.toThrow(); }); }); describe('toString()', () => { it('should be the same as Field(0)', async () => { const uint64 = new UInt64(0); const field = Field(0); expect(uint64.toString()).toEqual(field.toString()); }); it('should be the same as 2^53-1', async () => { const uint64 = new UInt64(String(NUMBERMAX)); const field = Field(String(NUMBERMAX)); expect(uint64.toString()).toEqual(field.toString()); }); }); describe('check()', () => { it('should pass checking a MAXINT', () => { expect(() => { UInt64.check(UInt64.MAXINT()); }).not.toThrow(); }); it('should throw checking over MAXINT', () => { const aboveMax = new UInt64(1); aboveMax.value = Field(1n << 64n); expect(() => { UInt64.check(aboveMax); }).toThrow(); }); }); describe('from() ', () => { describe('fromNumber()', () => { it('should be the same as Field(1)', () => { const uint = UInt64.from(1); expect(uint.value).toEqual(new UInt64(1).value); }); it('should be the same as 2^53-1', () => { const uint = UInt64.from(NUMBERMAX); expect(uint.value).toEqual(Field(String(NUMBERMAX))); }); }); describe('fromString()', () => { it('should be the same as Field(1)', () => { const uint = UInt64.from('1'); expect(uint.value).toEqual(new UInt64(1).value); }); it('should be the same as 2^53-1', () => { const uint = UInt64.from(String(NUMBERMAX)); expect(uint.value).toEqual(Field(String(NUMBERMAX))); }); }); }); }); }); describe('UInt32', () => { const NUMBERMAX = 2 ** 32 - 1; describe('Inside circuit', () => { describe('add', () => { it('1+1=2', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => new UInt32(1)); const y = Provable.witness(UInt32, () => new UInt32(1)); x.add(y).assertEquals(new UInt32(2)); }); }); it('5000+5000=10000', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => new UInt32(5000)); const y = Provable.witness(UInt32, () => new UInt32(5000)); x.add(y).assertEquals(new UInt32(10000)); }); }); it('(MAXINT/2+MAXINT/2) adds to MAXINT', async () => { const n = ((1n << 32n) - 2n) / 2n; await Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => new UInt32(n)); const y = Provable.witness(UInt32, () => new UInt32(n)); x.add(y).add(1).assertEquals(UInt32.MAXINT()); }); }); it('should throw on overflow addition', async () => { await expect( Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => UInt32.MAXINT()); const y = Provable.witness(UInt32, () => new UInt32(1)); x.add(y); }) ).rejects.toThrow(); }); }); describe('sub', () => { it('1-1=0', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => new UInt32(1)); const y = Provable.witness(UInt32, () => new UInt32(1)); x.sub(y).assertEquals(new UInt32(0)); }); }); it('10000-5000=5000', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => new UInt32(10000)); const y = Provable.witness(UInt32, () => new UInt32(5000)); x.sub(y).assertEquals(new UInt32(5000)); }); }); it('should throw on sub if results in negative number', async () => { await expect( Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => new UInt32(0)); const y = Provable.witness(UInt32, () => new UInt32(1)); x.sub(y); }) ).rejects.toThrow(); }); }); describe('mul', () => { it('1x2=2', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => new UInt32(1)); const y = Provable.witness(UInt32, () => new UInt32(2)); x.mul(y).assertEquals(new UInt32(2)); }); }); it('1x0=0', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => new UInt32(1)); const y = Provable.witness(UInt32, () => new UInt32(0)); x.mul(y).assertEquals(new UInt32(0)); }); }); it('1000x1000=1000000', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => new UInt32(1000)); const y = Provable.witness(UInt32, () => new UInt32(1000)); x.mul(y).assertEquals(new UInt32(1000000)); }); }); it('MAXINTx1=MAXINT', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => UInt32.MAXINT()); const y = Provable.witness(UInt32, () => new UInt32(1)); x.mul(y).assertEquals(UInt32.MAXINT()); }); }); it('should throw on overflow multiplication', async () => { await expect( Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => UInt32.MAXINT()); const y = Provable.witness(UInt32, () => new UInt32(2)); x.mul(y); }) ).rejects.toThrow(); }); }); describe('div', () => { it('2/1=2', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => new UInt32(2)); const y = Provable.witness(UInt32, () => new UInt32(1)); x.div(y).assertEquals(new UInt32(2)); }); }); it('0/1=0', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => new UInt32(0)); const y = Provable.witness(UInt32, () => new UInt32(1)); x.div(y).assertEquals(new UInt32(0)); }); }); it('2000/1000=2', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => new UInt32(2000)); const y = Provable.witness(UInt32, () => new UInt32(1000)); x.div(y).assertEquals(new UInt32(2)); }); }); it('MAXINT/1=MAXINT', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => UInt32.MAXINT()); const y = Provable.witness(UInt32, () => new UInt32(1)); x.div(y).assertEquals(UInt32.MAXINT()); }); }); it('should throw on division by zero', async () => { await expect( Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => UInt32.MAXINT()); const y = Provable.witness(UInt32, () => new UInt32(0)); x.div(y); }) ).rejects.toThrow(); }); }); describe('mod', () => { it('1%1=0', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => new UInt32(1)); const y = Provable.witness(UInt32, () => new UInt32(1)); x.mod(y).assertEquals(new UInt32(0)); }); }); it('500%32=20', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => new UInt32(500)); const y = Provable.witness(UInt32, () => new UInt32(32)); x.mod(y).assertEquals(new UInt32(20)); }); }); it('MAXINT%7=3', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => UInt32.MAXINT()); const y = Provable.witness(UInt32, () => new UInt32(7)); x.mod(y).assertEquals(new UInt32(3)); }); }); it('should throw on mod by zero', async () => { await expect( Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => UInt32.MAXINT()); const y = Provable.witness(UInt32, () => new UInt32(0)); x.mod(y).assertEquals(new UInt32(1)); }) ).rejects.toThrow(); }); }); describe('assertLt', () => { it('1<2=true', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => new UInt32(1)); const y = Provable.witness(UInt32, () => new UInt32(2)); x.assertLessThan(y); }); }); it('1<1=false', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => new UInt32(1)); const y = Provable.witness(UInt32, () => new UInt32(1)); x.assertLessThan(y); }).catch(() => {}); }); it('2<1=false', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => new UInt32(2)); const y = Provable.witness(UInt32, () => new UInt32(1)); x.assertLessThan(y); }).catch(() => {}); }); it('1000<100000=true', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => new UInt32(1000)); const y = Provable.witness(UInt32, () => new UInt32(100000)); x.assertLessThan(y); }); }); it('100000<1000=false', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => new UInt32(100000)); const y = Provable.witness(UInt32, () => new UInt32(1000)); x.assertLessThan(y); }).catch(() => {}); }); it('MAXINT<MAXINT=false', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => UInt32.MAXINT()); const y = Provable.witness(UInt32, () => UInt32.MAXINT()); x.assertLessThan(y); }).catch(() => {}); }); }); describe('assertLessThanOrEqual', () => { it('1<=1=true', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => new UInt32(1)); const y = Provable.witness(UInt32, () => new UInt32(1)); x.assertLessThanOrEqual(y); }); }); it('2<=1=false', async () => { await expect( Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => new UInt32(2)); const y = Provable.witness(UInt32, () => new UInt32(1)); x.assertLessThanOrEqual(y); }) ).rejects.toThrow(); }); it('1000<=100000=true', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => new UInt32(1000)); const y = Provable.witness(UInt32, () => new UInt32(100000)); x.assertLessThanOrEqual(y); }); }); it('100000<=1000=false', async () => { await expect( Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => new UInt32(100000)); const y = Provable.witness(UInt32, () => new UInt32(1000)); x.assertLessThanOrEqual(y); }) ).rejects.toThrow(); }); it('MAXINT<=MAXINT=true', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => UInt32.MAXINT()); const y = Provable.witness(UInt32, () => UInt32.MAXINT()); x.assertLessThanOrEqual(y); }); }); }); describe('assertGreaterThan', () => { it('2>1=true', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => new UInt32(2)); const y = Provable.witness(UInt32, () => new UInt32(1)); x.assertGreaterThan(y); }); }); it('1>1=false', async () => { await expect( Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => new UInt32(1)); const y = Provable.witness(UInt32, () => new UInt32(1)); x.assertGreaterThan(y); }) ).rejects.toThrow(); }); it('1>2=false', async () => { await expect( Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => new UInt32(1)); const y = Provable.witness(UInt32, () => new UInt32(2)); x.assertGreaterThan(y); }) ).rejects.toThrow(); }); it('100000>1000=true', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => new UInt32(100000)); const y = Provable.witness(UInt32, () => new UInt32(1000)); x.assertGreaterThan(y); }); }); it('1000>100000=false', async () => { await expect( Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => new UInt32(1000)); const y = Provable.witness(UInt32, () => new UInt32(100000)); x.assertGreaterThan(y); }) ).rejects.toThrow(); }); it('MAXINT>MAXINT=false', async () => { await expect( Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => UInt32.MAXINT()); const y = Provable.witness(UInt32, () => UInt32.MAXINT()); x.assertGreaterThan(y); }) ).rejects.toThrow(); }); }); describe('assertGreaterThanOrEqual', () => { it('1<=1=true', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => new UInt32(1)); const y = Provable.witness(UInt32, () => new UInt32(1)); x.assertGreaterThanOrEqual(y); }); }); it('1>=2=false', async () => { await expect( Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => new UInt32(1)); const y = Provable.witness(UInt32, () => new UInt32(2)); x.assertGreaterThanOrEqual(y); }) ).rejects.toThrow(); }); it('100000>=1000=true', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => new UInt32(100000)); const y = Provable.witness(UInt32, () => new UInt32(1000)); x.assertGreaterThanOrEqual(y); }); }); it('1000>=100000=false', async () => { await expect( Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => new UInt32(1000)); const y = Provable.witness(UInt32, () => new UInt32(100000)); x.assertGreaterThanOrEqual(y); }) ).rejects.toThrow(); }); it('MAXINT>=MAXINT=true', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => UInt32.MAXINT()); const y = Provable.witness(UInt32, () => UInt32.MAXINT()); x.assertGreaterThanOrEqual(y); }); }); }); describe('from() ', () => { describe('fromNumber()', () => { it('should be the same as Field(1)', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => UInt32.from(1)); const y = Provable.witness(UInt32, () => new UInt32(1)); x.assertEquals(y); }); }); it('should be the same as 2^53-1', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => UInt32.from(NUMBERMAX)); const y = Provable.witness( UInt32, () => new UInt32(String(NUMBERMAX)) ); x.assertEquals(y); }); }); }); describe('fromString()', () => { it('should be the same as Field(1)', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => UInt32.from('1')); const y = Provable.witness(UInt32, () => new UInt32(1)); x.assertEquals(y); }); }); it('should be the same as 2^53-1', async () => { await Provable.runAndCheck(async () => { const x = Provable.witness(UInt32, () => UInt32.from(String(NUMBERMAX)) ); const y = Provable.witness( UInt32, () => new UInt32(String(NUMBER