Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new hashing functions (SHA & Keccak) #999

Merged
merged 111 commits into from
Dec 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
111 commits
Select commit Hold shift + click to select a range
d281c36
feat(snarky.d.ts): add sha.create and sha.fieldBytesFromHex functions…
MartinMinkov Jun 21, 2023
c85a959
refactor(hash.ts): rename Hash to HashHelpers
MartinMinkov Jun 21, 2023
18e9afe
feat(hash.ts): add support for SHA224, SHA256, SHA385, SHA512, and Ke…
MartinMinkov Jun 21, 2023
556b81f
feat(index.ts): export Hash from lib/hash
MartinMinkov Jun 21, 2023
cb223a5
fix(hash.ts): correct SHA384 function name to match the correct lengt…
MartinMinkov Jun 21, 2023
8343232
feat(int.ts): add UInt8 class to represent 8-bit unsigned integers in…
MartinMinkov Jun 21, 2023
b6868e0
refactor(hash.ts): add support for hashing UInt8 values
MartinMinkov Jun 21, 2023
3f6da96
feat(keccak.ts): add tests for SHA224, SHA256, SHA384, SHA512, Poseid…
MartinMinkov Jun 21, 2023
c2bc474
Merge branch 'develop' into feat/add-sha
MartinMinkov Jun 26, 2023
43fb182
feat(bindings): update bindings
MartinMinkov Jun 26, 2023
20d4eb7
refactor(hash.ts): remove unnecessary check for empty message in buil…
MartinMinkov Jun 26, 2023
2d58c7e
refactor(hash.ts): remove Field type from buildSHA
MartinMinkov Jun 27, 2023
10bda74
refactor(hash.ts): return hash function for hash objects
MartinMinkov Jun 27, 2023
49a294b
refactor(keccak.ts): rename Hash.default to Hash.hash
MartinMinkov Jun 27, 2023
22977f5
refactor(hash.ts): change buildSHA function to return a UInt8 array i…
MartinMinkov Jun 27, 2023
42d9f74
feat(int.ts): add fromFields to UInt8
MartinMinkov Jun 27, 2023
957c1f8
feat(int.ts): add fromHex method to UInt8 class to convert hex string…
MartinMinkov Jun 27, 2023
ae01aa7
feat(int.ts): add static method toHex to UInt8 class to convert an ar…
MartinMinkov Jun 27, 2023
92deb9e
test(keccak.ts): add tests for checking hex->digest, digest->hex conv…
MartinMinkov Jun 27, 2023
b600b28
fix(int.ts): working impl of toHex for UInt8
MartinMinkov Jun 28, 2023
ecd62c4
feat(random.ts): add support for generating random UInt8 values
MartinMinkov Jun 28, 2023
8bd3a93
feat(int.ts): add bigint to constructor and introduce static NUM_BITS
MartinMinkov Jun 28, 2023
cd6a019
feat(int.ts): add static properties and to UInt8 class
MartinMinkov Jun 28, 2023
7fed256
chore(int.ts): add toString(), toBigInt(), toField(), and toJSON() me…
MartinMinkov Jun 28, 2023
8a97189
chore(int.ts): add static method MAXINT() to UInt8 class to return th…
MartinMinkov Jun 28, 2023
7176fb6
refactor(int.ts): change static method to instance method
MartinMinkov Jun 28, 2023
3c1bc94
feat(int.ts): add methods toJSON, toUInt32, and toUInt64 to the UInt8…
MartinMinkov Jun 28, 2023
e15f7e2
feat(int.ts): add from and private checkConstant methods
MartinMinkov Jun 28, 2023
321529b
refactor(int.ts): add isConstant() method to UInt8 class for checking…
MartinMinkov Jun 28, 2023
509c5f9
refactor(int.ts): add toConstant() method to UInt8 class
MartinMinkov Jun 28, 2023
325c49c
refactor(int.ts): add UInt8 to constructor
MartinMinkov Jun 28, 2023
d996d25
fix(int.ts): add support for string type in the constructor of UInt8 …
MartinMinkov Jun 28, 2023
738719c
test(keccack.unit-test.ts): start unit tests for the constructor of U…
MartinMinkov Jun 28, 2023
b7bcb03
test(keccack.unit-test.ts): add unit test for handling numbers up to …
MartinMinkov Jun 28, 2023
64135db
test(keccack.unit-test.ts): add unit tests for negative numbers and n…
MartinMinkov Jun 28, 2023
05550d9
feat(keccack.unit-test.ts): add tests for digest to hex and hex to di…
MartinMinkov Jun 28, 2023
de47924
fix(int.ts): add type checking for UInt32 and UInt64
MartinMinkov Jun 28, 2023
6c2b45d
feat(int.ts): add arithmetic operations (add, sub, mul, div, mod) to …
MartinMinkov Jun 28, 2023
fc75970
feat(int.ts): add assertion methods for comparing UInt8 values
MartinMinkov Jun 28, 2023
be58d9a
feat(int.ts): add more unit tests for UInt8
MartinMinkov Jun 29, 2023
88c687f
feat(keccack.unit-test.ts): add support for provable testing
MartinMinkov Jun 29, 2023
e432819
refactor(keccak): rename keccack -> keccak
MartinMinkov Jun 29, 2023
71b4ee7
refactor(keccak.unit-test.ts): remove checkHashOutCircuit
MartinMinkov Jun 29, 2023
db79cd3
feat(vk_regression): add hashing to vk regression tests
MartinMinkov Jun 29, 2023
36e145f
fix(keccak-test): replace usage of ctor with .from
MartinMinkov Jun 29, 2023
4360afe
feat(examples): start debugging hashing example
MartinMinkov Jun 29, 2023
5885af0
fix(keccak.ts): fix equals function to correctly compare UInt8 arrays
MartinMinkov Jun 29, 2023
f86b23c
refactor(hash.ts): remove unused code and variables for better code c…
MartinMinkov Jun 29, 2023
068fb4d
feat(UInt8): refactor ctor to use .from instead
MartinMinkov Jun 30, 2023
b59bb90
feat(uint8): add most doc comments
MartinMinkov Jul 3, 2023
2fdafc6
chore(uint8: add TODO comments for more efficient range checking
MartinMinkov Jul 3, 2023
3e24ff7
refactor(hash.ts): move fromHex and toHex from UInt8 to Hash namespace
MartinMinkov Jul 3, 2023
003c1ca
feat(keccak): add ocaml unit tests
MartinMinkov Jul 3, 2023
b1c5042
Revert "refactor(hash.ts): move fromHex and toHex from UInt8 to Hash …
MartinMinkov Jul 5, 2023
c0a3fa5
feat(bindings): update bindings
MartinMinkov Jul 5, 2023
553ef3a
feat(uint8): add scaffold for rangeCheck it works for proofs
MartinMinkov Jul 5, 2023
70aa753
Merge branch 'develop' into feat/add-sha
MartinMinkov Jul 5, 2023
bec639a
chore(uint8): add rangeCheck todo comments
MartinMinkov Jul 5, 2023
93d5bd6
Merge branch 'develop' into feat/add-sha
MartinMinkov Jul 14, 2023
77ccc7c
fix(hash.ts): use MlArray.to() instead of array literal for Snarky.sh…
MartinMinkov Jul 15, 2023
e73d5bf
chore(bindings): update bindings
MartinMinkov Jul 15, 2023
f8a7c14
Merge branch 'feature/keccak-and-ecdsa' into feat/add-sha
mitschabaude Dec 13, 2023
08448a8
missing from merge
mitschabaude Dec 13, 2023
763d38f
remove some unnecessary changes
mitschabaude Dec 13, 2023
6fd370d
work on uint8 and make it compile
mitschabaude Dec 13, 2023
900a344
export Hash, rename old Hash to HashHelpers
mitschabaude Dec 13, 2023
3bbd454
add rangeCheck16
mitschabaude Dec 13, 2023
0e04807
fix divMod
mitschabaude Dec 13, 2023
5da4f72
fix and polish uint8
mitschabaude Dec 13, 2023
ac58ebd
add doc comments
Trivo25 Dec 13, 2023
025cc9a
minor
Trivo25 Dec 13, 2023
7caffae
provable bytes type
mitschabaude Dec 13, 2023
fca04f8
use bytes as keccak input
mitschabaude Dec 13, 2023
da919b7
tweaks to bytes type
mitschabaude Dec 13, 2023
3d8dbbd
adapt bytes consumers
mitschabaude Dec 13, 2023
644f279
fix import cycle
mitschabaude Dec 13, 2023
eadb423
adapt keccak unit test
mitschabaude Dec 13, 2023
3ee7d19
fix length assertion
mitschabaude Dec 13, 2023
8b4344a
fix something very stupid
mitschabaude Dec 13, 2023
0a896bd
add constant tests
mitschabaude Dec 13, 2023
5d15141
Update src/lib/keccak.ts
Trivo25 Dec 13, 2023
aa1bb04
Update src/lib/keccak.ts
Trivo25 Dec 13, 2023
25bcd0c
Update src/lib/keccak.ts
Trivo25 Dec 13, 2023
bb4f5bd
Update src/lib/keccak.ts
Trivo25 Dec 13, 2023
008df18
Update src/lib/keccak.ts
Trivo25 Dec 13, 2023
fc7a861
Update src/lib/keccak.ts
Trivo25 Dec 13, 2023
0651999
Update src/lib/keccak.ts
Trivo25 Dec 13, 2023
542ce92
Update src/lib/keccak.ts
Trivo25 Dec 13, 2023
1e39026
Update src/lib/keccak.ts
Trivo25 Dec 13, 2023
82e5847
Update src/lib/keccak.ts
Trivo25 Dec 13, 2023
51226af
Update src/lib/keccak.ts
Trivo25 Dec 13, 2023
b97b1aa
Update src/lib/keccak.ts
Trivo25 Dec 13, 2023
ad69dbb
Update src/lib/keccak.ts
Trivo25 Dec 13, 2023
489db6b
Update src/lib/keccak.ts
Trivo25 Dec 13, 2023
ca1c02e
add verbose argument to nonprovable equivalence test
mitschabaude Dec 13, 2023
0fbc626
run keccak unit tests outside circuit for now
mitschabaude Dec 13, 2023
e5810f4
make old unit tests work
mitschabaude Dec 13, 2023
1cb8b0b
add toFields and expose Bytes
mitschabaude Dec 13, 2023
4729c8b
fix examples
mitschabaude Dec 13, 2023
0769e6a
fix cs example
mitschabaude Dec 13, 2023
231e87c
vk regression
mitschabaude Dec 13, 2023
12f0b2d
add toInput
mitschabaude Dec 13, 2023
3408b43
Merge branch 'feature/keccak-doccomments' into feat/add-sha
mitschabaude Dec 14, 2023
7b305fb
support bytes from string without constructing type of specific length
mitschabaude Dec 14, 2023
9d444b9
adapt keccak doccomments to bytes input
mitschabaude Dec 14, 2023
3be3ac5
Hash doccomments
mitschabaude Dec 14, 2023
4ad851e
don't double-constrain uint8 results
mitschabaude Dec 14, 2023
7ac389a
improve uint8 docs
mitschabaude Dec 14, 2023
accc779
fix int test
mitschabaude Dec 14, 2023
7b6ace4
bytes to test utils
mitschabaude Dec 14, 2023
8d52779
merge old and new unit tests
mitschabaude Dec 14, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/bindings
47 changes: 8 additions & 39 deletions src/examples/crypto/ecdsa/ecdsa.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,34 @@ import {
createEcdsa,
createForeignCurve,
Bool,
Struct,
Provable,
Field,
Keccak,
Gadgets,
Bytes,
mitschabaude marked this conversation as resolved.
Show resolved Hide resolved
} from 'o1js';

export { keccakAndEcdsa, ecdsa, Secp256k1, Ecdsa, Message32 };
export { keccakAndEcdsa, ecdsa, Secp256k1, Ecdsa, Bytes32 };

class Secp256k1 extends createForeignCurve(Crypto.CurveParams.Secp256k1) {}
class Scalar extends Secp256k1.Scalar {}
class Ecdsa extends createEcdsa(Secp256k1) {}
class Message32 extends Message(32) {}
class Bytes32 extends Bytes(32) {}

const keccakAndEcdsa = ZkProgram({
name: 'ecdsa',
publicInput: Message32,
publicInput: Bytes32.provable,
publicOutput: Bool,

methods: {
verifyEcdsa: {
privateInputs: [Ecdsa.provable, Secp256k1.provable],
method(message: Message32, signature: Ecdsa, publicKey: Secp256k1) {
return signature.verify(message.array, publicKey);
method(message: Bytes32, signature: Ecdsa, publicKey: Secp256k1) {
return signature.verify(message, publicKey);
},
},

sha3: {
privateInputs: [],
method(message: Message32) {
Keccak.nistSha3(256, message.array);
method(message: Bytes32) {
Keccak.nistSha3(256, message);
return Bool(true);
},
},
Expand All @@ -55,31 +52,3 @@ const ecdsa = ZkProgram({
},
},
});

// helper: class for a message of n bytes

function Message(lengthInBytes: number) {
return class Message extends Struct({
array: Provable.Array(Field, lengthInBytes),
}) {
static from(message: string | Uint8Array) {
if (typeof message === 'string') {
message = new TextEncoder().encode(message);
}
let padded = new Uint8Array(32);
padded.set(message);
return new this({ array: [...padded].map(Field) });
}

toBytes() {
return Uint8Array.from(this.array.map((f) => Number(f)));
}

/**
* Important: check that inputs are, in fact, bytes
*/
static check(msg: { array: Field[] }) {
msg.array.forEach(Gadgets.rangeCheck8);
}
};
}
4 changes: 2 additions & 2 deletions src/examples/crypto/ecdsa/run.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Secp256k1, Ecdsa, keccakAndEcdsa, Message32, ecdsa } from './ecdsa.js';
import { Secp256k1, Ecdsa, keccakAndEcdsa, ecdsa, Bytes32 } from './ecdsa.js';
import assert from 'assert';

// create an example ecdsa signature

let privateKey = Secp256k1.Scalar.random();
let publicKey = Secp256k1.generator.scale(privateKey);

let message = Message32.from("what's up");
let message = Bytes32.fromString("what's up");

let signature = Ecdsa.sign(message.toBytes(), privateKey.toBigInt());

Expand Down
49 changes: 49 additions & 0 deletions src/examples/zkapps/hashing/hash.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import {
Hash,
Field,
SmartContract,
state,
State,
method,
Permissions,
Bytes,
} from 'o1js';

let initialCommitment: Field = Field(0);

export class HashStorage extends SmartContract {
@state(Field) commitment = State<Field>();

init() {
super.init();
this.account.permissions.set({
...Permissions.default(),
editState: Permissions.proofOrSignature(),
});
this.commitment.set(initialCommitment);
}

@method SHA256(xs: Bytes) {
const shaHash = Hash.SHA3_256.hash(xs);
const commitment = Hash.hash(shaHash.toFields());
this.commitment.set(commitment);
}

@method SHA384(xs: Bytes) {
const shaHash = Hash.SHA3_384.hash(xs);
const commitment = Hash.hash(shaHash.toFields());
this.commitment.set(commitment);
}

@method SHA512(xs: Bytes) {
const shaHash = Hash.SHA3_512.hash(xs);
const commitment = Hash.hash(shaHash.toFields());
this.commitment.set(commitment);
}

@method Keccak256(xs: Bytes) {
const shaHash = Hash.Keccak256.hash(xs);
const commitment = Hash.hash(shaHash.toFields());
this.commitment.set(commitment);
}
}
73 changes: 73 additions & 0 deletions src/examples/zkapps/hashing/run.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { HashStorage } from './hash.js';
import { Mina, PrivateKey, AccountUpdate, Bytes } from 'o1js';

let txn;
let proofsEnabled = true;
// setup local ledger
let Local = Mina.LocalBlockchain({ proofsEnabled });
Mina.setActiveInstance(Local);

if (proofsEnabled) {
console.log('Proofs enabled');
HashStorage.compile();
}

// test accounts that pays all the fees, and puts additional funds into the zkapp
const feePayer = Local.testAccounts[0];

// zkapp account
const zkAppPrivateKey = PrivateKey.random();
const zkAppAddress = zkAppPrivateKey.toPublicKey();
const zkAppInstance = new HashStorage(zkAppAddress);

// 0, 1, 2, 3, ..., 32
const hashData = Bytes.from(Array.from({ length: 32 }, (_, i) => i));

console.log('Deploying Hash Example....');
txn = await Mina.transaction(feePayer.publicKey, () => {
AccountUpdate.fundNewAccount(feePayer.publicKey);
zkAppInstance.deploy();
});
await txn.sign([feePayer.privateKey, zkAppPrivateKey]).send();

const initialState =
Mina.getAccount(zkAppAddress).zkapp?.appState?.[0].toString();

let currentState;
console.log('Initial State', initialState);

console.log(`Updating commitment from ${initialState} using SHA256 ...`);
txn = await Mina.transaction(feePayer.publicKey, () => {
zkAppInstance.SHA256(hashData);
});
await txn.prove();
await txn.sign([feePayer.privateKey]).send();
currentState = Mina.getAccount(zkAppAddress).zkapp?.appState?.[0].toString();
console.log(`Current state successfully updated to ${currentState}`);

console.log(`Updating commitment from ${initialState} using SHA384 ...`);
txn = await Mina.transaction(feePayer.publicKey, () => {
zkAppInstance.SHA384(hashData);
});
await txn.prove();
await txn.sign([feePayer.privateKey]).send();
currentState = Mina.getAccount(zkAppAddress).zkapp?.appState?.[0].toString();
console.log(`Current state successfully updated to ${currentState}`);

console.log(`Updating commitment from ${initialState} using SHA512 ...`);
txn = await Mina.transaction(feePayer.publicKey, () => {
zkAppInstance.SHA512(hashData);
});
await txn.prove();
await txn.sign([feePayer.privateKey]).send();
currentState = Mina.getAccount(zkAppAddress).zkapp?.appState?.[0].toString();
console.log(`Current state successfully updated to ${currentState}`);

console.log(`Updating commitment from ${initialState} using Keccak256...`);
txn = await Mina.transaction(feePayer.publicKey, () => {
zkAppInstance.Keccak256(hashData);
});
await txn.prove();
await txn.sign([feePayer.privateKey]).send();
currentState = Mina.getAccount(zkAppAddress).zkapp?.appState?.[0].toString();
console.log(`Current state successfully updated to ${currentState}`);
4 changes: 3 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export { createForeignCurve, ForeignCurve } from './lib/foreign-curve.js';
export { createEcdsa, EcdsaSignature } from './lib/foreign-ecdsa.js';
export { Poseidon, TokenSymbol } from './lib/hash.js';
export { Keccak } from './lib/keccak.js';
export { Hash } from './lib/hashes-combined.js';

export * from './lib/signature.js';
export type {
Expand All @@ -31,7 +32,8 @@ export {
} from './lib/circuit_value.js';
export { Provable } from './lib/provable.js';
export { Circuit, Keypair, public_, circuitMain } from './lib/circuit.js';
export { UInt32, UInt64, Int64, Sign } from './lib/int.js';
export { UInt32, UInt64, Int64, Sign, UInt8 } from './lib/int.js';
export { Bytes } from './lib/provable-types/provable-types.js';
export { Gadgets } from './lib/gadgets/gadgets.js';
export { Types } from './bindings/mina-transaction/types.js';

Expand Down
19 changes: 10 additions & 9 deletions src/lib/foreign-ecdsa.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ import { AlmostForeignField } from './foreign-field.js';
import { assert } from './gadgets/common.js';
import { Field3 } from './gadgets/foreign-field.js';
import { Ecdsa } from './gadgets/elliptic-curve.js';
import { Field } from './field.js';
import { l } from './gadgets/range-check.js';
import { Keccak } from './keccak.js';
import { Bytes } from './provable-types/provable-types.js';
import { UInt8 } from './int.js';

// external API
export { createEcdsa, EcdsaSignature };
Expand Down Expand Up @@ -99,7 +100,7 @@ class EcdsaSignature {
* isValid.assertTrue('signature verifies');
* ```
*/
verify(message: Field[], publicKey: FlexiblePoint) {
verify(message: Bytes, publicKey: FlexiblePoint) {
let msgHashBytes = Keccak.ethereum(message);
let msgHash = keccakOutputToScalar(msgHashBytes, this.Constructor.Curve);
return this.verifySignedHash(msgHash, publicKey);
Expand Down Expand Up @@ -132,8 +133,7 @@ class EcdsaSignature {
* Note: This method is not provable, and only takes JS bigints as input.
*/
static sign(message: (bigint | number)[] | Uint8Array, privateKey: bigint) {
let msgFields = [...message].map(Field.from);
let msgHashBytes = Keccak.ethereum(msgFields);
let msgHashBytes = Keccak.ethereum(message);
let msgHash = keccakOutputToScalar(msgHashBytes, this.Curve);
return this.signHash(msgHash.toBigInt(), privateKey);
}
Expand Down Expand Up @@ -228,7 +228,7 @@ function toObject(signature: EcdsaSignature) {
* - takes a 32 bytes hash
* - converts them to 3 limbs which collectively have L_n <= 256 bits
*/
function keccakOutputToScalar(hash: Field[], Curve: typeof ForeignCurve) {
function keccakOutputToScalar(hash: Bytes, Curve: typeof ForeignCurve) {
const L_n = Curve.Scalar.sizeInBits;
// keep it simple for now, avoid dealing with dropping bits
// TODO: what does "leftmost bits" mean? big-endian or little-endian?
Expand All @@ -240,14 +240,15 @@ function keccakOutputToScalar(hash: Field[], Curve: typeof ForeignCurve) {
// piece together into limbs
// bytes are big-endian, so the first byte is the most significant
assert(l === 88n);
let x2 = bytesToLimbBE(hash.slice(0, 10));
let x1 = bytesToLimbBE(hash.slice(10, 21));
let x0 = bytesToLimbBE(hash.slice(21, 32));
let x2 = bytesToLimbBE(hash.bytes.slice(0, 10));
let x1 = bytesToLimbBE(hash.bytes.slice(10, 21));
let x0 = bytesToLimbBE(hash.bytes.slice(21, 32));

return new Curve.Scalar.AlmostReduced([x0, x1, x2]);
}

function bytesToLimbBE(bytes: Field[]) {
function bytesToLimbBE(bytes_: UInt8[]) {
let bytes = bytes_.map((x) => x.value);
let n = bytes.length;
let limb = bytes[0];
for (let i = 1; i < n; i++) {
Expand Down
10 changes: 10 additions & 0 deletions src/lib/gadgets/gadgets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import {
compactMultiRangeCheck,
multiRangeCheck,
rangeCheck16,
rangeCheck64,
rangeCheck8,
} from './range-check.js';
Expand Down Expand Up @@ -41,6 +42,15 @@ const Gadgets = {
return rangeCheck64(x);
},

/**
* Asserts that the input value is in the range [0, 2^16).
*
* See {@link Gadgets.rangeCheck64} for analogous details and usage examples.
*/
rangeCheck16(x: Field) {
return rangeCheck16(x);
},

/**
* Asserts that the input value is in the range [0, 2^8).
*
Expand Down
20 changes: 19 additions & 1 deletion src/lib/gadgets/range-check.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@ import { Field } from '../field.js';
import { Gates } from '../gates.js';
import { assert, bitSlice, exists, toVar, toVars } from './common.js';

export { rangeCheck64, rangeCheck8, multiRangeCheck, compactMultiRangeCheck };
export {
rangeCheck64,
rangeCheck8,
rangeCheck16,
multiRangeCheck,
compactMultiRangeCheck,
};
export { l, l2, l3, lMask, l2Mask };

/**
Expand Down Expand Up @@ -208,6 +214,18 @@ function rangeCheck1Helper(inputs: {
);
}

function rangeCheck16(x: Field) {
if (x.isConstant()) {
assert(
x.toBigInt() < 1n << 16n,
`rangeCheck16: expected field to fit in 8 bits, got ${x}`
);
return;
}
// check that x fits in 16 bits
x.rangeCheckHelper(16).assertEquals(x);
}

function rangeCheck8(x: Field) {
if (x.isConstant()) {
assert(
Expand Down
21 changes: 19 additions & 2 deletions src/lib/gadgets/test-utils.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import type { FiniteField } from '../../bindings/crypto/finite_field.js';
import { ProvableSpec } from '../testing/equivalent.js';
import { ProvableSpec, spec } from '../testing/equivalent.js';
import { Random } from '../testing/random.js';
import { Gadgets } from './gadgets.js';
import { assert } from './common.js';
import { Bytes } from '../provable-types/provable-types.js';

export { foreignField, unreducedForeignField, uniformForeignField, throwError };
export {
foreignField,
unreducedForeignField,
uniformForeignField,
bytes,
throwError,
};

const { Field3 } = Gadgets;

Expand Down Expand Up @@ -49,6 +56,16 @@ function uniformForeignField(
};
}

function bytes(length: number) {
const Bytes_ = Bytes(length);
return spec<Uint8Array, Bytes>({
rng: Random.map(Random.bytes(length), (x) => Uint8Array.from(x)),
there: Bytes_.from,
back: (x) => x.toBytes(),
provable: Bytes_.provable,
});
}

// helper

function throwError<T>(message: string): T {
Expand Down
Loading