Skip to content

Commit a1a12b7

Browse files
Merge pull request #1055 from ProvableHQ/feat/boolean-integer-types-support
Add Boolean type
2 parents e17086b + 5367eed commit a1a12b7

File tree

6 files changed

+242
-2
lines changed

6 files changed

+242
-2
lines changed

sdk/src/browser.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ export { logAndThrow } from "./utils.js";
6060
export {
6161
Address,
6262
Authorization,
63+
Boolean,
6364
BHP256,
6465
BHP512,
6566
BHP768,

sdk/src/wasm.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
export {
22
Address,
33
Authorization,
4+
Boolean,
45
BHP256,
56
BHP512,
67
BHP768,

sdk/tests/arithmetic.test.ts

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import sinon from "sinon";
22
import { expect } from "chai";
3-
import { Field, Scalar, Group} from "../src/node.js";
3+
import { Field, Scalar, Group, Boolean} from "../src/node.js";
44
import { FieldGenerator, GroupGenerator, ScalarGenerator } from "./data/algebra.js";
55

66
describe('Field and Group Arithmetic Tests', () => {
@@ -44,6 +44,58 @@ describe('Field and Group Arithmetic Tests', () => {
4444
expect(two_power_four.equals(two_times_eight)).equal(true);
4545
});
4646

47+
it('Check boolean creation and serialization', () => {
48+
const t = Boolean.fromString("true");
49+
const f = Boolean.fromString("false");
50+
51+
expect(t.toString()).equals("true");
52+
expect(f.toString()).equals("false");
53+
54+
const tBytes = t.toBytesLe();
55+
const fBytes = f.toBytesLe();
56+
57+
const tFromBytes = Boolean.fromBytesLe(tBytes);
58+
const fFromBytes = Boolean.fromBytesLe(fBytes);
59+
60+
expect(t.equals(tFromBytes)).equals(true);
61+
expect(f.equals(fFromBytes)).equals(true);
62+
63+
const tBits = t.toBitsLe();
64+
const fBits = f.toBitsLe();
65+
66+
const tFromBits = Boolean.fromBitsLe(tBits);
67+
const fFromBits = Boolean.fromBitsLe(fBits);
68+
69+
expect(t.equals(tFromBits)).equals(true);
70+
expect(f.equals(fFromBits)).equals(true);
71+
});
72+
73+
it('Check boolean logical operations', () => {
74+
const t = new Boolean(true);
75+
const f = new Boolean(false);
76+
77+
expect(t.not().toString()).equals("false");
78+
expect(f.not().toString()).equals("true");
79+
80+
expect(t.and(t).toString()).equals("true");
81+
expect(t.and(f).toString()).equals("false");
82+
expect(f.and(f).toString()).equals("false");
83+
84+
expect(t.or(t).toString()).equals("true");
85+
expect(t.or(f).toString()).equals("true");
86+
expect(f.or(f).toString()).equals("false");
87+
88+
expect(t.xor(t).toString()).equals("false");
89+
expect(t.xor(f).toString()).equals("true");
90+
expect(f.xor(f).toString()).equals("false");
91+
92+
expect(t.nand(t).toString()).equals("false");
93+
expect(t.nand(f).toString()).equals("true");
94+
95+
expect(f.nor(f).toString()).equals("true");
96+
expect(t.nor(f).toString()).equals("false");
97+
});
98+
4799
it('Check scalar field arithmetic', () => {
48100
// Create the 2 scalar element.
49101
const a = Scalar.fromString("2scalar");

wasm/src/types/boolean.rs

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
// Copyright (C) 2019-2025 Provable Inc.
2+
// This file is part of the Provable SDK library.
3+
4+
// The Provable SDK library is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
9+
// The Provable SDK library is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU General Public License for more details.
13+
14+
// You should have received a copy of the GNU General Public License
15+
// along with the Provable SDK library. If not, see <https://www.gnu.org/licenses/>.
16+
17+
use crate::{
18+
Plaintext,
19+
from_js_typed_array,
20+
to_bits_array_le,
21+
types::native::{BooleanNative, LiteralNative, PlaintextNative},
22+
};
23+
use snarkvm_console::prelude::{FromBits, FromBytes, ToBits, ToBytes};
24+
use snarkvm_wasm::utilities::Uniform;
25+
26+
use js_sys::{Array, Uint8Array};
27+
use once_cell::sync::OnceCell;
28+
use std::{ops::Deref, str::FromStr};
29+
use wasm_bindgen::prelude::*;
30+
31+
/// Boolean element.
32+
#[wasm_bindgen]
33+
#[derive(Clone, Debug, Eq, PartialEq)]
34+
pub struct Boolean(BooleanNative);
35+
36+
#[wasm_bindgen]
37+
impl Boolean {
38+
/// Creates a Boolean from a native JS bool.
39+
#[wasm_bindgen(constructor)]
40+
pub fn new(value: bool) -> Boolean {
41+
Boolean(BooleanNative::new(value))
42+
}
43+
44+
/// Creates a boolean object from a string representation ("true"/"false").
45+
#[wasm_bindgen(js_name = "fromString")]
46+
#[allow(clippy::should_implement_trait)]
47+
pub fn from_string(boolean: &str) -> Result<Boolean, String> {
48+
Ok(Self(BooleanNative::from_str(boolean).map_err(|e| e.to_string())?))
49+
}
50+
51+
/// Returns the string representation of the boolean element.
52+
#[wasm_bindgen(js_name = "toString")]
53+
#[allow(clippy::inherent_to_string)]
54+
pub fn to_string(&self) -> String {
55+
self.0.to_string()
56+
}
57+
58+
/// Create a boolean element from a Uint8Array of left endian bytes.
59+
#[wasm_bindgen(js_name = "fromBytesLe")]
60+
pub fn from_bytes_le(bytes: &Uint8Array) -> Result<Boolean, String> {
61+
let bytes = bytes.to_vec();
62+
let boolean = BooleanNative::from_bytes_le(&bytes).map_err(|e| e.to_string())?;
63+
Ok(Boolean(boolean))
64+
}
65+
66+
/// Encode the boolean element as a Uint8Array of left endian bytes.
67+
#[wasm_bindgen(js_name = "toBytesLe")]
68+
pub fn to_bytes_le(&self) -> Result<Uint8Array, String> {
69+
let bytes = self.0.to_bytes_le().map_err(|e| e.to_string())?;
70+
Ok(Uint8Array::from(bytes.as_slice()))
71+
}
72+
73+
/// Reconstruct a boolean element from a boolean array representation.
74+
#[wasm_bindgen(js_name = "fromBitsLe")]
75+
pub fn from_bits_le(bits: &Array) -> Result<Boolean, String> {
76+
let bit_vec = from_js_typed_array!(bits, as_bool, "boolean")?;
77+
if bit_vec.len() != 1 {
78+
return Err("Boolean expects exactly 1 bit".to_string());
79+
}
80+
let boolean = BooleanNative::from_bits_le(&bit_vec).map_err(|e| e.to_string())?;
81+
Ok(Boolean(boolean))
82+
}
83+
84+
/// Get the left endian boolean array representation of the boolean element.
85+
#[wasm_bindgen(js_name = "toBitsLe")]
86+
pub fn to_bits_le(&self) -> Array {
87+
to_bits_array_le!(self)
88+
}
89+
90+
/// Create a plaintext from the boolean element.
91+
#[wasm_bindgen(js_name = "toPlaintext")]
92+
pub fn to_plaintext(&self) -> Plaintext {
93+
Plaintext::from(PlaintextNative::Literal(LiteralNative::Boolean(self.0), OnceCell::new()))
94+
}
95+
96+
/// Clone the boolean element.
97+
#[allow(clippy::should_implement_trait)]
98+
pub fn clone(&self) -> Boolean {
99+
Boolean(self.0)
100+
}
101+
102+
/// Generate a random boolean element.
103+
pub fn random() -> Boolean {
104+
let rng = &mut rand::thread_rng();
105+
Boolean(BooleanNative::rand(rng))
106+
}
107+
108+
/// Logical NOT.
109+
pub fn not(&self) -> Boolean {
110+
Boolean(!self.0)
111+
}
112+
113+
/// Logical AND.
114+
pub fn and(&self, other: &Boolean) -> Boolean {
115+
Boolean(self.0 & other.0)
116+
}
117+
118+
/// Logical OR.
119+
pub fn or(&self, other: &Boolean) -> Boolean {
120+
Boolean(self.0 | other.0)
121+
}
122+
123+
/// Logical XOR.
124+
pub fn xor(&self, other: &Boolean) -> Boolean {
125+
Boolean(self.0 ^ other.0)
126+
}
127+
128+
/// Logical NAND.
129+
pub fn nand(&self, other: &Boolean) -> Boolean {
130+
Boolean(!(self.0 & other.0))
131+
}
132+
133+
/// Logical NOR.
134+
pub fn nor(&self, other: &Boolean) -> Boolean {
135+
Boolean(!(self.0 | other.0))
136+
}
137+
138+
/// Check if one boolean element equals another.
139+
pub fn equals(&self, other: &Boolean) -> bool {
140+
self.0 == BooleanNative::from(other)
141+
}
142+
}
143+
144+
impl Deref for Boolean {
145+
type Target = BooleanNative;
146+
147+
fn deref(&self) -> &Self::Target {
148+
&self.0
149+
}
150+
}
151+
152+
impl From<BooleanNative> for Boolean {
153+
fn from(native: BooleanNative) -> Self {
154+
Self(native)
155+
}
156+
}
157+
158+
impl From<Boolean> for BooleanNative {
159+
fn from(boolean: Boolean) -> Self {
160+
boolean.0
161+
}
162+
}
163+
164+
impl From<&BooleanNative> for Boolean {
165+
fn from(native: &BooleanNative) -> Self {
166+
Self(*native)
167+
}
168+
}
169+
170+
impl From<&Boolean> for BooleanNative {
171+
fn from(boolean: &Boolean) -> Self {
172+
boolean.0
173+
}
174+
}
175+
176+
impl FromStr for Boolean {
177+
type Err = anyhow::Error;
178+
179+
fn from_str(boolean: &str) -> Result<Self, Self::Err> {
180+
Ok(Self(BooleanNative::from_str(boolean)?))
181+
}
182+
}

wasm/src/types/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
// You should have received a copy of the GNU General Public License
1515
// along with the Provable SDK library. If not, see <https://www.gnu.org/licenses/>.
1616

17+
pub mod boolean;
18+
pub use boolean::Boolean;
19+
1720
pub mod field;
1821
pub use field::Field;
1922

wasm/src/types/native/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ use snarkvm_console::{
3434
Value,
3535
ValueType,
3636
},
37-
types::{Field, Group, Scalar, U16, U64},
37+
types::{Boolean, Field, Group, Scalar, U16, U64},
3838
};
3939
use snarkvm_ledger_block::{Execution, Input, Output, Transaction, Transition};
4040
use snarkvm_ledger_query::Query;
@@ -55,6 +55,7 @@ pub type SignatureNative = Signature<CurrentNetwork>;
5555
pub type ViewKeyNative = ViewKey<CurrentNetwork>;
5656

5757
// Algebraic & Primitive Data Types
58+
pub type BooleanNative = Boolean<CurrentNetwork>;
5859
pub type FieldNative = Field<CurrentNetwork>;
5960
pub type GroupNative = Group<CurrentNetwork>;
6061
pub type ScalarNative = Scalar<CurrentNetwork>;

0 commit comments

Comments
 (0)