Skip to content
Open
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
66922dc
merge + initial scaffolding
saefstroem Apr 11, 2026
b9dbe17
Implement zk sdk
saefstroem Apr 12, 2026
156ca8b
Update mod.rs
saefstroem Apr 12, 2026
5ea0fb5
Merge branch 'covpp-reset2' into zk-sdk
saefstroem Apr 20, 2026
d25305c
Update sdk
saefstroem Apr 20, 2026
d771435
Update sdk
saefstroem Apr 20, 2026
f893dbd
Remove unneeded deps
saefstroem Apr 20, 2026
260c9cb
Update Cargo.lock
saefstroem Apr 20, 2026
1cdebb7
Update error.rs
saefstroem Apr 20, 2026
3209ce8
risc0: use serialized VK and r0 byte parsing
saefstroem Apr 25, 2026
d235c6b
Merge branch 'covpp-reset2' into zk-sdk
saefstroem May 1, 2026
43f9657
Add comments + clippy
saefstroem May 1, 2026
1e005c7
Add R0 zk_to_script builders and groth16 support
saefstroem May 5, 2026
786814a
Merge branch 'covpp-reset2' into zk-sdk
saefstroem May 5, 2026
e062651
Merge remote-tracking branch 'upstream/toccata' into zk-sdk
saefstroem May 5, 2026
88527d2
Update zk builder and Cargo.lock for risc0/groth16
saefstroem May 5, 2026
b1cadf6
clippy
saefstroem May 5, 2026
41de812
Add wasm
saefstroem May 5, 2026
3bad7a7
Updated test examples
saefstroem May 5, 2026
538eb42
Update js test scripts to use compute budget and new tx version
saefstroem May 5, 2026
5798082
fmt
saefstroem May 5, 2026
373f780
revert devnet change
saefstroem May 5, 2026
0e11699
remove
saefstroem May 5, 2026
a136c51
Update all js examples
saefstroem May 6, 2026
10acbd7
fix toml
saefstroem May 6, 2026
b603891
Merge branch 'toccata' into zk-sdk
saefstroem May 13, 2026
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
514 changes: 439 additions & 75 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ license = "ISC"
repository = "https://github.com/kaspanet/rusty-kaspa"
edition = "2024"
include = [
"src/**/*.rs",
"src/*risc0-zkvm.workspace*/*.rs",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this intentional or a leftover? why does that path need special treatment here?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right must be a leftover, fixing.

"src/**/*.s",
"src/**/*.r",
"proto/**/*.proto",
Expand Down Expand Up @@ -225,6 +225,7 @@ md-5 = "0.10.6"
num = "0.4.1"
num_cpus = "1.16.0"
num-traits = "0.2.17"
num-bigint = "0.4.6"
once_cell = { version = "1.18.0", default-features = false }
pad = "0.1.6"
parking_lot = "0.12.1"
Expand All @@ -244,6 +245,7 @@ risc0-circuit-keccak = { version="4.0.3", default-features=false }
risc0-zkp = "3.0.3"
risc0-core = "3.0.0"
risc0-binfmt = "3.0.3"
risc0-zkvm = { version = "3.0.3", default-features = false }
ripemd = { version = "0.1.3", default-features = false }
rlimit = "0.10.1"
rocksdb = "0.24.0"
Expand Down
7 changes: 6 additions & 1 deletion crypto/txscript/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ borsh.workspace = true
cfg-if.workspace = true
faster-hex.workspace = true
hexplay.workspace = true
hex.workspace = true
indexmap.workspace = true
itertools.workspace = true
kaspa-addresses.workspace = true
Expand All @@ -39,12 +40,15 @@ kaspa-txscript-errors.workspace = true
kaspa-utils.workspace = true
kaspa-wasm-core = { workspace = true, optional = true }
log.workspace = true
num-bigint.workspace = true
parking_lot.workspace = true
rand.workspace = true
risc0-binfmt.workspace = true
risc0-circuit-recursion.workspace = true
risc0-core.workspace = true
risc0-zkp.workspace = true
risc0-zkvm.workspace = true
risc0-groth16.workspace = true
secp256k1.workspace = true
serde-wasm-bindgen.workspace = true
serde.workspace = true
Expand All @@ -55,6 +59,7 @@ thiserror.workspace = true
wasm-bindgen.workspace = true
workflow-wasm.workspace = true


[build-dependencies]
cc = { workspace = true }

Expand All @@ -65,7 +70,7 @@ rayon.workspace = true
kaspa-core.workspace = true
serde_json.workspace = true
smallvec.workspace = true

bincode.workspace = true
[[bench]]
name = "zk_precompiles"
path = "benches/zk_precompiles.rs"
Expand Down
1 change: 1 addition & 0 deletions crypto/txscript/src/wasm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ cfg_if! {

pub use self::opcodes::*;
pub use self::builder::*;
pub use crate::zk_precompiles::risc0::zk_to_script::wasm::R0ScriptBuilder;
}
}
10 changes: 10 additions & 0 deletions crypto/txscript/src/zk_precompiles/fields/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,16 @@ impl Fr {
}
}

impl TryInto<Vec<u8>> for Fr {
type Error = FieldsError;

fn try_into(self) -> Result<Vec<u8>, Self::Error> {
let mut bytes = Vec::new();
self.0.serialize_uncompressed(&mut bytes).map_err(FieldsError::ArkSerialization)?;
Ok(bytes)
}
}

impl TryFrom<&[u8]> for Fr {
type Error = FieldsError;

Expand Down
1 change: 1 addition & 0 deletions crypto/txscript/src/zk_precompiles/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
mod error;
mod fields;
pub mod groth16;
mod points;
pub mod risc0;
pub mod tags;
pub mod tests;
Expand Down
11 changes: 11 additions & 0 deletions crypto/txscript/src/zk_precompiles/points/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use thiserror::Error;

#[derive(Debug, Error)]
pub enum PointError {
#[error("Malformed G1 field element")]
MalformedG1,
#[error("Malformed G2 field element")]
MalformedG2,
#[error("Ark deserialization error: {0}")]
ArkDeserialization(#[from] ark_serialize::SerializationError),
}
57 changes: 57 additions & 0 deletions crypto/txscript/src/zk_precompiles/points/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
mod error;
use ark_bn254::{G1Affine, G2Affine};
use ark_serialize::CanonicalDeserialize;

pub trait PointFromBytes<'input>: Sized {
type Input: ?Sized;
fn from_r0_bytes(bytes: &'input Self::Input) -> Result<Self, PointError>;
}
pub use error::PointError;
pub struct G1(pub G1Affine);
pub struct G2(pub G2Affine);

impl<'input> PointFromBytes<'input> for G1 {
type Input = Vec<Vec<u8>>;

/// Deserialize an element over the G1 group from r0 bytes in big-endian format
fn from_r0_bytes(bytes: &Self::Input) -> Result<G1, PointError> {
if bytes.len() != 2 {
return Err(PointError::MalformedG1);
}
let g1_affine: Vec<u8> = bytes[0].iter().rev().chain(bytes[1].iter().rev()).cloned().collect();
Comment on lines +14 to +21
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why shout it be 2 dimensional reversed vectors?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

r0 stores in BE order whilst ark expects LE, but I agree here that the fn name should be more specific to r0, not generic from_bytes


Ok(G1(G1Affine::deserialize_uncompressed(&*g1_affine)?))
}
}

impl<'input> PointFromBytes<'input> for G2 {
type Input = Vec<Vec<Vec<u8>>>;

fn from_r0_bytes(bytes: &Self::Input) -> Result<G2, PointError> {
if bytes.len() != 2 || bytes[0].len() != 2 || bytes[1].len() != 2 {
return Err(PointError::MalformedG2);
}
let g2_affine: Vec<u8> = bytes[0][1]
.iter()
.rev()
.chain(bytes[0][0].iter().rev())
.chain(bytes[1][1].iter().rev())
.chain(bytes[1][0].iter().rev())
.cloned()
.collect();
Comment on lines +31 to +41
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why shout it be 2 dimensional reversed vectors?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see above


Ok(G2(G2Affine::deserialize_uncompressed(&*g2_affine)?))
}
}

impl From<G1> for G1Affine {
fn from(g1: G1) -> G1Affine {
g1.0
}
}

impl From<G2> for G2Affine {
fn from(g2: G2) -> G2Affine {
g2.0
}
}
21 changes: 21 additions & 0 deletions crypto/txscript/src/zk_precompiles/risc0/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ use kaspa_txscript_errors::TxScriptError;
use risc0_zkp::verify::VerificationError;
use thiserror::Error;

use crate::zk_precompiles::fields::error::FieldsError;

#[derive(Debug, Error)]
pub enum R0Error {
#[error("Std io error: {0}")]
Expand All @@ -28,4 +30,23 @@ pub enum R0Error {
Merkle,
#[error("Invalid BabyBearElem in seal")]
SealHasInvalidBabyBearElem,
#[error("Script builder error: {0}")]
ScriptBuilder(#[from] crate::script_builder::ScriptBuilderError),

#[error("Fields error: {0}")]
Fields(#[from] FieldsError),

#[error("Seal decoding error: {0}")]
SealDecoding(String),

#[error("Bincode VK serialization failed")]
BincodeVkSerialization,

#[error("Point error: {0}")]
Point(#[from] crate::zk_precompiles::points::PointError),

#[error("Ark serialization error: {0}")]
ArkSerialization(#[from] ark_serialize::SerializationError),
#[error("Parse bigint error: {0}")]
ParseBigInt(#[from] num_bigint::ParseBigIntError),
}
2 changes: 2 additions & 0 deletions crypto/txscript/src/zk_precompiles/risc0/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ mod error;
pub mod merkle;
pub mod rcpt;
pub mod receipt_claim;
mod result;
pub mod zk_to_script;

pub struct R0SuccinctPrecompile;
pub use error::R0Error;
Expand Down
14 changes: 13 additions & 1 deletion crypto/txscript/src/zk_precompiles/risc0/rcpt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,19 @@ impl TryFrom<u8> for HashFnId {
}
}

impl TryFrom<&str> for HashFnId {
type Error = R0Error;

fn try_from(value: &str) -> Result<Self, Self::Error> {
match value {
"blake2b" => Ok(HashFnId::Blake2b),
"poseidon2" => Ok(HashFnId::Poseidon2),
"sha-256" => Ok(HashFnId::Sha256),
_ => Err(R0Error::InvalidHashFnId(value.as_bytes().first().copied().unwrap_or(255))),
}
}
}

impl From<HashFnId> for u8 {
fn from(value: HashFnId) -> Self {
value as u8
Expand All @@ -70,7 +83,6 @@ pub struct SuccinctReceipt {
/// The control ID of this receipt, identifying the recursion program that was run (e.g. lift,
/// join, or resolve).
control_id: Digest,

/// Claim containing information about the computation that this receipt proves.
///
/// The standard claim type is [ReceiptClaim][crate::ReceiptClaim], which represents a RISC-V
Expand Down
3 changes: 3 additions & 0 deletions crypto/txscript/src/zk_precompiles/risc0/result.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
use crate::zk_precompiles::risc0::R0Error;

pub type Result<T> = std::result::Result<T, R0Error>;
Loading
Loading