mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-01-09 22:57:59 -05:00
zkas: Implement debug symbols in the compiled binary
This commit is contained in:
@@ -133,7 +133,7 @@ impl RlnIdentity {
|
||||
vec![epoch, external_nullifier, x, y, internal_nullifier, identity_root.inner()];
|
||||
|
||||
info!(target: "crypto::rln::create_proof", "[RLN] Creating proof for event {}", event.id());
|
||||
let signal_zkbin = ZkBinary::decode(RLN2_SIGNAL_ZKBIN)?;
|
||||
let signal_zkbin = ZkBinary::decode(RLN2_SIGNAL_ZKBIN, false)?;
|
||||
let signal_circuit = ZkCircuit::new(witnesses, &signal_zkbin);
|
||||
|
||||
let proof = Proof::create(proving_key, &[signal_circuit], &public_inputs, &mut OsRng)?;
|
||||
|
||||
@@ -603,7 +603,7 @@ impl Client {
|
||||
let identity_tree: MerkleTree = deserialize_async(&identity_tree).await?;
|
||||
|
||||
// Retrieve the ZK proving key from the db
|
||||
let signal_zkbin = ZkBinary::decode(RLN2_SIGNAL_ZKBIN)?;
|
||||
let signal_zkbin = ZkBinary::decode(RLN2_SIGNAL_ZKBIN, false)?;
|
||||
let signal_circuit = ZkCircuit::new(empty_witnesses(&signal_zkbin)?, &signal_zkbin);
|
||||
let Some(proving_key) = self.server.server_store.get("rlnv2-diff-signal-pk")? else {
|
||||
return Err(Error::DatabaseError(
|
||||
|
||||
@@ -155,7 +155,7 @@ impl IrcServer {
|
||||
let rln_identity_store = darkirc.sled.open_tree("rln_identity_store")?;
|
||||
|
||||
// Generate RLN proving and verifying keys, if needed
|
||||
let rln_signal_zkbin = ZkBinary::decode(RLN2_SIGNAL_ZKBIN)?;
|
||||
let rln_signal_zkbin = ZkBinary::decode(RLN2_SIGNAL_ZKBIN, false)?;
|
||||
let rln_signal_circuit =
|
||||
ZkCircuit::new(empty_witnesses(&rln_signal_zkbin)?, &rln_signal_zkbin);
|
||||
|
||||
@@ -184,7 +184,7 @@ impl IrcServer {
|
||||
|
||||
if server_store.get("rlnv2-diff-slash-pk")?.is_none() {
|
||||
info!(target: "irc::server", "[RLN] Creating RlnV2_Diff_Slash ProvingKey");
|
||||
let zkbin = ZkBinary::decode(RLN2_SLASH_ZKBIN)?;
|
||||
let zkbin = ZkBinary::decode(RLN2_SLASH_ZKBIN, false)?;
|
||||
let circuit = ZkCircuit::new(empty_witnesses(&zkbin).unwrap(), &zkbin);
|
||||
let provingkey = ProvingKey::build(zkbin.k, &circuit);
|
||||
let mut buf = vec![];
|
||||
@@ -194,7 +194,7 @@ impl IrcServer {
|
||||
|
||||
if server_store.get("rlnv2-diff-slash-vk")?.is_none() {
|
||||
info!(target: "irc::server", "[RLN] Creating RlnV2_Diff_Slash VerifyingKey");
|
||||
let zkbin = ZkBinary::decode(RLN2_SIGNAL_ZKBIN)?;
|
||||
let zkbin = ZkBinary::decode(RLN2_SIGNAL_ZKBIN, false)?;
|
||||
let circuit = ZkCircuit::new(empty_witnesses(&zkbin).unwrap(), &zkbin);
|
||||
let verifyingkey = VerifyingKey::build(zkbin.k, &circuit);
|
||||
let mut buf = vec![];
|
||||
|
||||
@@ -2126,7 +2126,7 @@ impl Drk {
|
||||
return Err(Error::Custom("Fee circuit not found".to_string()))
|
||||
};
|
||||
|
||||
let fee_zkbin = ZkBinary::decode(&fee_zkbin.1)?;
|
||||
let fee_zkbin = ZkBinary::decode(&fee_zkbin.1, false)?;
|
||||
|
||||
let fee_circuit = ZkCircuit::new(empty_witnesses(&fee_zkbin)?, &fee_zkbin);
|
||||
|
||||
@@ -2141,7 +2141,7 @@ impl Drk {
|
||||
return Err(Error::DatabaseError("[dao_mint] DAO Mint circuit not found".to_string()))
|
||||
};
|
||||
|
||||
let dao_mint_zkbin = ZkBinary::decode(&dao_mint_zkbin.1)?;
|
||||
let dao_mint_zkbin = ZkBinary::decode(&dao_mint_zkbin.1, false)?;
|
||||
|
||||
let dao_mint_circuit = ZkCircuit::new(empty_witnesses(&dao_mint_zkbin)?, &dao_mint_zkbin);
|
||||
|
||||
@@ -2464,7 +2464,7 @@ impl Drk {
|
||||
))
|
||||
};
|
||||
|
||||
let fee_zkbin = ZkBinary::decode(&fee_zkbin.1)?;
|
||||
let fee_zkbin = ZkBinary::decode(&fee_zkbin.1, false)?;
|
||||
|
||||
let fee_circuit = ZkCircuit::new(empty_witnesses(&fee_zkbin)?, &fee_zkbin);
|
||||
|
||||
@@ -2490,8 +2490,8 @@ impl Drk {
|
||||
))
|
||||
};
|
||||
|
||||
let propose_burn_zkbin = ZkBinary::decode(&propose_burn_zkbin.1)?;
|
||||
let propose_main_zkbin = ZkBinary::decode(&propose_main_zkbin.1)?;
|
||||
let propose_burn_zkbin = ZkBinary::decode(&propose_burn_zkbin.1, false)?;
|
||||
let propose_main_zkbin = ZkBinary::decode(&propose_main_zkbin.1, false)?;
|
||||
|
||||
let propose_burn_circuit =
|
||||
ZkCircuit::new(empty_witnesses(&propose_burn_zkbin)?, &propose_burn_zkbin);
|
||||
@@ -2644,7 +2644,7 @@ impl Drk {
|
||||
return Err(Error::Custom("[dao_generic_proposal_tx] Fee circuit not found".to_string()))
|
||||
};
|
||||
|
||||
let fee_zkbin = ZkBinary::decode(&fee_zkbin.1)?;
|
||||
let fee_zkbin = ZkBinary::decode(&fee_zkbin.1, false)?;
|
||||
|
||||
let fee_circuit = ZkCircuit::new(empty_witnesses(&fee_zkbin)?, &fee_zkbin);
|
||||
|
||||
@@ -2670,8 +2670,8 @@ impl Drk {
|
||||
))
|
||||
};
|
||||
|
||||
let propose_burn_zkbin = ZkBinary::decode(&propose_burn_zkbin.1)?;
|
||||
let propose_main_zkbin = ZkBinary::decode(&propose_main_zkbin.1)?;
|
||||
let propose_burn_zkbin = ZkBinary::decode(&propose_burn_zkbin.1, false)?;
|
||||
let propose_main_zkbin = ZkBinary::decode(&propose_main_zkbin.1, false)?;
|
||||
|
||||
let propose_burn_circuit =
|
||||
ZkCircuit::new(empty_witnesses(&propose_burn_zkbin)?, &propose_burn_zkbin);
|
||||
@@ -2848,7 +2848,7 @@ impl Drk {
|
||||
return Err(Error::Custom("[dao_vote] Fee circuit not found".to_string()))
|
||||
};
|
||||
|
||||
let fee_zkbin = ZkBinary::decode(&fee_zkbin.1)?;
|
||||
let fee_zkbin = ZkBinary::decode(&fee_zkbin.1, false)?;
|
||||
|
||||
let fee_circuit = ZkCircuit::new(empty_witnesses(&fee_zkbin)?, &fee_zkbin);
|
||||
|
||||
@@ -2870,8 +2870,8 @@ impl Drk {
|
||||
return Err(Error::Custom("[dao_vote] DAO Vote Main circuit not found".to_string()))
|
||||
};
|
||||
|
||||
let dao_vote_burn_zkbin = ZkBinary::decode(&dao_vote_burn_zkbin.1)?;
|
||||
let dao_vote_main_zkbin = ZkBinary::decode(&dao_vote_main_zkbin.1)?;
|
||||
let dao_vote_burn_zkbin = ZkBinary::decode(&dao_vote_burn_zkbin.1, false)?;
|
||||
let dao_vote_main_zkbin = ZkBinary::decode(&dao_vote_main_zkbin.1, false)?;
|
||||
|
||||
let dao_vote_burn_circuit =
|
||||
ZkCircuit::new(empty_witnesses(&dao_vote_burn_zkbin)?, &dao_vote_burn_zkbin);
|
||||
@@ -3110,9 +3110,9 @@ impl Drk {
|
||||
return Err(Error::Custom("[dao_exec_transfer] Fee circuit not found".to_string()))
|
||||
};
|
||||
|
||||
let mint_zkbin = ZkBinary::decode(&mint_zkbin.1)?;
|
||||
let burn_zkbin = ZkBinary::decode(&burn_zkbin.1)?;
|
||||
let fee_zkbin = ZkBinary::decode(&fee_zkbin.1)?;
|
||||
let mint_zkbin = ZkBinary::decode(&mint_zkbin.1, false)?;
|
||||
let burn_zkbin = ZkBinary::decode(&burn_zkbin.1, false)?;
|
||||
let fee_zkbin = ZkBinary::decode(&fee_zkbin.1, false)?;
|
||||
|
||||
let mint_circuit = ZkCircuit::new(empty_witnesses(&mint_zkbin)?, &mint_zkbin);
|
||||
let burn_circuit = ZkCircuit::new(empty_witnesses(&burn_zkbin)?, &burn_zkbin);
|
||||
@@ -3155,10 +3155,10 @@ impl Drk {
|
||||
))
|
||||
};
|
||||
|
||||
let dao_exec_zkbin = ZkBinary::decode(&dao_exec_zkbin.1)?;
|
||||
let dao_auth_transfer_zkbin = ZkBinary::decode(&dao_auth_transfer_zkbin.1)?;
|
||||
let dao_exec_zkbin = ZkBinary::decode(&dao_exec_zkbin.1, false)?;
|
||||
let dao_auth_transfer_zkbin = ZkBinary::decode(&dao_auth_transfer_zkbin.1, false)?;
|
||||
let dao_auth_transfer_enc_coin_zkbin =
|
||||
ZkBinary::decode(&dao_auth_transfer_enc_coin_zkbin.1)?;
|
||||
ZkBinary::decode(&dao_auth_transfer_enc_coin_zkbin.1, false)?;
|
||||
|
||||
let dao_exec_circuit = ZkCircuit::new(empty_witnesses(&dao_exec_zkbin)?, &dao_exec_zkbin);
|
||||
let dao_auth_transfer_circuit =
|
||||
@@ -3403,7 +3403,7 @@ impl Drk {
|
||||
else {
|
||||
return Err(Error::Custom("[dao_exec_generic] Fee circuit not found".to_string()))
|
||||
};
|
||||
let fee_zkbin = ZkBinary::decode(&fee_zkbin.1)?;
|
||||
let fee_zkbin = ZkBinary::decode(&fee_zkbin.1, false)?;
|
||||
let fee_circuit = ZkCircuit::new(empty_witnesses(&fee_zkbin)?, &fee_zkbin);
|
||||
let fee_pk = ProvingKey::build(fee_zkbin.k, &fee_circuit);
|
||||
|
||||
@@ -3422,7 +3422,7 @@ impl Drk {
|
||||
"[dao_exec_generic] DAO {namespace} circuit not found"
|
||||
)))
|
||||
};
|
||||
let dao_exec_zkbin = ZkBinary::decode(&dao_exec_zkbin.1)?;
|
||||
let dao_exec_zkbin = ZkBinary::decode(&dao_exec_zkbin.1, false)?;
|
||||
let dao_exec_circuit = ZkCircuit::new(empty_witnesses(&dao_exec_zkbin)?, &dao_exec_zkbin);
|
||||
let dao_exec_pk = ProvingKey::build(dao_exec_zkbin.k, &dao_exec_circuit);
|
||||
|
||||
|
||||
@@ -540,7 +540,7 @@ impl Drk {
|
||||
return Err(Error::Custom("[deploy_contract] Fee circuit not found".to_string()))
|
||||
};
|
||||
|
||||
let fee_zkbin = ZkBinary::decode(&fee_zkbin.1)?;
|
||||
let fee_zkbin = ZkBinary::decode(&fee_zkbin.1, false)?;
|
||||
|
||||
let fee_circuit = ZkCircuit::new(empty_witnesses(&fee_zkbin)?, &fee_zkbin);
|
||||
|
||||
@@ -603,7 +603,7 @@ impl Drk {
|
||||
return Err(Error::Custom("[lock_contract] Fee circuit not found".to_string()))
|
||||
};
|
||||
|
||||
let fee_zkbin = ZkBinary::decode(&fee_zkbin.1)?;
|
||||
let fee_zkbin = ZkBinary::decode(&fee_zkbin.1, false)?;
|
||||
|
||||
let fee_circuit = ZkCircuit::new(empty_witnesses(&fee_zkbin)?, &fee_zkbin);
|
||||
|
||||
|
||||
@@ -1400,7 +1400,7 @@ impl Drk {
|
||||
return Err(Error::Custom("Fee circuit not found".to_string()))
|
||||
};
|
||||
|
||||
let fee_zkbin = ZkBinary::decode(&fee_zkbin.1)?;
|
||||
let fee_zkbin = ZkBinary::decode(&fee_zkbin.1, false)?;
|
||||
|
||||
let fee_circuit = ZkCircuit::new(empty_witnesses(&fee_zkbin)?, &fee_zkbin);
|
||||
|
||||
|
||||
@@ -125,8 +125,8 @@ impl Drk {
|
||||
return Err(Error::Custom("Burn circuit not found".to_string()))
|
||||
};
|
||||
|
||||
let mint_zkbin = ZkBinary::decode(&mint_zkbin.1)?;
|
||||
let burn_zkbin = ZkBinary::decode(&burn_zkbin.1)?;
|
||||
let mint_zkbin = ZkBinary::decode(&mint_zkbin.1, false)?;
|
||||
let burn_zkbin = ZkBinary::decode(&burn_zkbin.1, false)?;
|
||||
|
||||
let mint_circuit = ZkCircuit::new(empty_witnesses(&mint_zkbin)?, &mint_zkbin);
|
||||
let burn_circuit = ZkCircuit::new(empty_witnesses(&burn_zkbin)?, &burn_zkbin);
|
||||
@@ -228,8 +228,8 @@ impl Drk {
|
||||
return Err(Error::Custom("Burn circuit not found".to_string()))
|
||||
};
|
||||
|
||||
let mint_zkbin = ZkBinary::decode(&mint_zkbin.1)?;
|
||||
let burn_zkbin = ZkBinary::decode(&burn_zkbin.1)?;
|
||||
let mint_zkbin = ZkBinary::decode(&mint_zkbin.1, false)?;
|
||||
let burn_zkbin = ZkBinary::decode(&burn_zkbin.1, false)?;
|
||||
|
||||
let mint_circuit = ZkCircuit::new(empty_witnesses(&mint_zkbin)?, &mint_zkbin);
|
||||
let burn_circuit = ZkCircuit::new(empty_witnesses(&burn_zkbin)?, &burn_zkbin);
|
||||
|
||||
@@ -301,9 +301,9 @@ impl Drk {
|
||||
return Err(Error::Custom("Fee circuit not found".to_string()))
|
||||
};
|
||||
|
||||
let mint_zkbin = ZkBinary::decode(&mint_zkbin.1)?;
|
||||
let auth_mint_zkbin = ZkBinary::decode(&auth_mint_zkbin.1)?;
|
||||
let fee_zkbin = ZkBinary::decode(&fee_zkbin.1)?;
|
||||
let mint_zkbin = ZkBinary::decode(&mint_zkbin.1, false)?;
|
||||
let auth_mint_zkbin = ZkBinary::decode(&auth_mint_zkbin.1, false)?;
|
||||
let fee_zkbin = ZkBinary::decode(&fee_zkbin.1, false)?;
|
||||
|
||||
let mint_circuit = ZkCircuit::new(empty_witnesses(&mint_zkbin)?, &mint_zkbin);
|
||||
let auth_mint_circuit =
|
||||
@@ -409,8 +409,8 @@ impl Drk {
|
||||
return Err(Error::Custom("Fee circuit not found".to_string()))
|
||||
};
|
||||
|
||||
let auth_mint_zkbin = ZkBinary::decode(&auth_mint_zkbin.1)?;
|
||||
let fee_zkbin = ZkBinary::decode(&fee_zkbin.1)?;
|
||||
let auth_mint_zkbin = ZkBinary::decode(&auth_mint_zkbin.1, false)?;
|
||||
let fee_zkbin = ZkBinary::decode(&fee_zkbin.1, false)?;
|
||||
|
||||
let auth_mint_circuit =
|
||||
ZkCircuit::new(empty_witnesses(&auth_mint_zkbin)?, &auth_mint_zkbin);
|
||||
|
||||
@@ -95,9 +95,9 @@ impl Drk {
|
||||
return Err(Error::Custom("Fee circuit not found".to_string()))
|
||||
};
|
||||
|
||||
let mint_zkbin = ZkBinary::decode(&mint_zkbin.1)?;
|
||||
let burn_zkbin = ZkBinary::decode(&burn_zkbin.1)?;
|
||||
let fee_zkbin = ZkBinary::decode(&fee_zkbin.1)?;
|
||||
let mint_zkbin = ZkBinary::decode(&mint_zkbin.1, false)?;
|
||||
let burn_zkbin = ZkBinary::decode(&burn_zkbin.1, false)?;
|
||||
let fee_zkbin = ZkBinary::decode(&fee_zkbin.1, false)?;
|
||||
|
||||
let mint_circuit = ZkCircuit::new(empty_witnesses(&mint_zkbin)?, &mint_zkbin);
|
||||
let burn_circuit = ZkCircuit::new(empty_witnesses(&burn_zkbin)?, &burn_zkbin);
|
||||
|
||||
@@ -164,7 +164,7 @@ fn main() -> ExitCode {
|
||||
println!("Wrote output to {}", &output);
|
||||
|
||||
if eflag {
|
||||
let zkbin = ZkBinary::decode(&bincode).unwrap();
|
||||
let zkbin = ZkBinary::decode(&bincode, true).unwrap();
|
||||
println!("{zkbin:#?}");
|
||||
}
|
||||
|
||||
|
||||
@@ -28,17 +28,18 @@ from darkfi_sdk.zkas import (MockProver, ZkBinary, ZkCircuit, ProvingKey,
|
||||
def eprint(fstr, *args):
|
||||
print("error: " + fstr, *args, file=sys.stderr)
|
||||
|
||||
def show_trace(opcodes, trace):
|
||||
print(f"{'Line':<4} {'Opcode':<22} {'Type':<10} {'Values'}")
|
||||
def show_trace(zkbin, opcodes, trace):
|
||||
print(f"{'Line':<6} {'Source':<12} {'Opcode':<22} {'Result':<20} {'Values'}")
|
||||
for i, (opcode, (optype, args)) in enumerate(zip(opcodes, trace)):
|
||||
if args:
|
||||
args = ", ".join([str(arg) for arg in args])
|
||||
args = f"[{args}]"
|
||||
else:
|
||||
args = ""
|
||||
opcode = str(opcode)
|
||||
optype = str(optype)
|
||||
print(f"{i:<4} {opcode:<22} {optype:<10} {args}")
|
||||
# Get source location from debug info
|
||||
loc = zkbin.opcode_location(i)
|
||||
source = f"L{loc[0]}:C{loc[1]}" if loc else "-"
|
||||
|
||||
# Get result variable name for assignments
|
||||
result = zkbin.heap_name(i) or "-" # Simplified - would need proper heap tracking
|
||||
|
||||
args_str = f"[{', '.join(str(a) for a in args)}]" if args else ""
|
||||
print(f"{i:<6} {source:<12} {str(opcode):<22} {result:<20} {args_str}")
|
||||
|
||||
def load_circuit_witness(circuit, witness_file):
|
||||
# We attempt to decode the witnesses from the JSON file.
|
||||
@@ -147,7 +148,7 @@ def main(witness_file, source_file, mock=False, trace=False):
|
||||
return -3
|
||||
|
||||
if trace:
|
||||
show_trace(zkbin.opcodes(), circuit.opvalues())
|
||||
show_trace(zkbin, zkbin.opcodes(), circuit.opvalues())
|
||||
|
||||
print("Verifying ZK proof...")
|
||||
verify_status = proof.verify(verifying_key, instances)
|
||||
|
||||
@@ -25,8 +25,8 @@ CONSTANT_TYPE CONSTANT_NAME
|
||||
CONSTANT_TYPE CONSTANT_NAME
|
||||
...
|
||||
.literal
|
||||
LITERAL
|
||||
LITERAL
|
||||
LITERAL_TYPE LITERAL_VALUE
|
||||
LITERAL_TYPE LITERAL_VALUE
|
||||
...
|
||||
.witness
|
||||
WITNESS_TYPE
|
||||
@@ -36,8 +36,10 @@ WITNESS_TYPE
|
||||
OPCODE ARG_NUM HEAP_TYPE HEAP_INDEX ... HEAP_TYPE HEAP_INDEX
|
||||
OPCODE ARG_NUM HEAP_TYPE HEAP_INDEX ... HEAP_TYPE HEAP_INDEX
|
||||
...
|
||||
.debug
|
||||
TBD
|
||||
.debug (optional)
|
||||
NUM_OPCODES [LINE COLUMN] ...
|
||||
HEAP_SIZE [HEAP_NAME] ...
|
||||
NUM_LITERALS [LITERAL_NAME] ...
|
||||
```
|
||||
|
||||
Integers in the binary are encoded using variable-integer encoding.
|
||||
@@ -129,7 +131,40 @@ the heap and become available for later references.
|
||||
|
||||
### `.debug`
|
||||
|
||||
TBD
|
||||
The `.debug` section is optional and contains debug information that
|
||||
maps the compiled binary back to the original source code. This is
|
||||
useful for debugging circuit failures when only the compiled binary
|
||||
is available.
|
||||
|
||||
> `NUM_OPCODES [LINE COLUMN] ... HEAP_SIZE [HEAP_NAME] ... NUM_LITERALS [LITERAL_NAME] ...`
|
||||
|
||||
where:
|
||||
|
||||
| Element | Description |
|
||||
|-----------------|------------------------------------------------------------------|
|
||||
| `NUM_OPCODES` | Number of opcodes in the `.circuit` section (VarInt) |
|
||||
| `LINE` | Source line number for this opcode (VarInt) |
|
||||
| `COLUMN` | Source column number for this opcode (VarInt) |
|
||||
| `HEAP_SIZE` | Total number of entries on the heap (VarInt) |
|
||||
| `HEAP_NAME` | Variable name for this heap entry (String) |
|
||||
| `NUM_LITERALS` | Number of literals in the `.literal` section (VarInt) |
|
||||
| `LITERAL_NAME` | The literal value as a string, e.g., "42" (String) |
|
||||
|
||||
The heap names are serialized in heap order: constants first, then
|
||||
witnesses, then assigned variables from circuit statements. This
|
||||
ordering matches the order in which items are pushed onto the heap
|
||||
during compilation.
|
||||
|
||||
Using the debug info, a debugger or tracing tool can display output
|
||||
such as:
|
||||
|
||||
```
|
||||
Line Source Opcode Variable Value
|
||||
0 L23:C5 EcMulShort token_commit [0x3a2f..., 0x91bc...]
|
||||
1 L24:C5 EcMulBase rcpt_commit [0x7d1e..., 0x44fa...]
|
||||
2 L25:C5 EcAdd commitment [0x8b3c..., 0x22de...]
|
||||
3 L26:C5 ConstrainInstance - -
|
||||
```
|
||||
|
||||
## Syntax Reference
|
||||
|
||||
|
||||
@@ -267,7 +267,7 @@ fn main() -> Result<()> {
|
||||
continue
|
||||
}
|
||||
let mut reader = Cursor::new(pk);
|
||||
let zkbin = ZkBinary::decode(&bincode)?;
|
||||
let zkbin = ZkBinary::decode(&bincode, false)?;
|
||||
let circuit = ZkCircuit::new(empty_witnesses(&zkbin)?, &zkbin);
|
||||
let proving_key = ProvingKey::read(&mut reader, circuit)?;
|
||||
mint = Some((proving_key, zkbin));
|
||||
|
||||
@@ -97,7 +97,7 @@ fn main() {
|
||||
// Signalling
|
||||
// ==========
|
||||
let signal_zkbin = include_bytes!("../signal.zk.bin");
|
||||
let signal_zkbin = ZkBinary::decode(signal_zkbin).unwrap();
|
||||
let signal_zkbin = ZkBinary::decode(signal_zkbin, false).unwrap();
|
||||
let signal_empty_circuit =
|
||||
ZkCircuit::new(empty_witnesses(&signal_zkbin).unwrap(), &signal_zkbin);
|
||||
|
||||
|
||||
@@ -17,16 +17,16 @@
|
||||
*/
|
||||
|
||||
use std::{
|
||||
fs::{File, read_dir},
|
||||
fs::{read_dir, File},
|
||||
io::{Read, Write},
|
||||
path::Path,
|
||||
};
|
||||
|
||||
use darkfi::{
|
||||
zk::{Proof, ProvingKey, VerifyingKey, Witness, ZkCircuit, empty_witnesses},
|
||||
zk::{empty_witnesses, Proof, ProvingKey, VerifyingKey, Witness, ZkCircuit},
|
||||
zkas::ZkBinary,
|
||||
};
|
||||
use darkfi_sdk::pasta::{Eq, Fp, pallas::Base};
|
||||
use darkfi_sdk::pasta::{pallas::Base, Eq, Fp};
|
||||
use darkfi_serial::serialize;
|
||||
use halo2_proofs::dev::CircuitCost;
|
||||
use rand::rngs::OsRng;
|
||||
@@ -83,7 +83,7 @@ fn main() {
|
||||
let mut file = File::open(&path).unwrap();
|
||||
let mut buf = vec![];
|
||||
file.read_to_end(&mut buf).unwrap();
|
||||
let zkbin = ZkBinary::decode(&buf).unwrap();
|
||||
let zkbin = ZkBinary::decode(&buf, false).unwrap();
|
||||
|
||||
// Get witnesses and public inputs for that particular zk file
|
||||
let (witnesses, public_inputs) = retrieve_proof_inputs(name);
|
||||
|
||||
@@ -24,9 +24,9 @@ use std::{
|
||||
};
|
||||
|
||||
use darkfi::{
|
||||
Result,
|
||||
zk::{Proof, VerifyingKey, ZkCircuit, empty_witnesses},
|
||||
zk::{empty_witnesses, Proof, VerifyingKey, ZkCircuit},
|
||||
zkas::ZkBinary,
|
||||
Result,
|
||||
};
|
||||
use darkfi_sdk::pasta::pallas::Base;
|
||||
use darkfi_serial::deserialize;
|
||||
@@ -66,7 +66,7 @@ fn main() -> Result<()> {
|
||||
file.read_to_end(&mut public_inputs_bin)?;
|
||||
|
||||
// Deserialize and Verify
|
||||
let zkbin = ZkBinary::decode(&bincode)?;
|
||||
let zkbin = ZkBinary::decode(&bincode, false)?;
|
||||
let verifier_witnesses = empty_witnesses(&zkbin)?;
|
||||
|
||||
// Create the circuit
|
||||
|
||||
@@ -188,7 +188,7 @@ impl ContractStore {
|
||||
let (zkbin, vkbin): (Vec<u8>, Vec<u8>) = deserialize(&zkas_bytes).unwrap();
|
||||
|
||||
// The first vec is the compiled zkas binary
|
||||
let zkbin = ZkBinary::decode(&zkbin).unwrap();
|
||||
let zkbin = ZkBinary::decode(&zkbin, false).unwrap();
|
||||
|
||||
// Construct the circuit to be able to read the VerifyingKey
|
||||
let circuit = ZkCircuit::new(empty_witnesses(&zkbin).unwrap(), &zkbin);
|
||||
@@ -484,7 +484,7 @@ impl ContractStoreOverlay {
|
||||
let (zkbin, vkbin): (Vec<u8>, Vec<u8>) = deserialize(&zkas_bytes).unwrap();
|
||||
|
||||
// The first vec is the compiled zkas binary
|
||||
let zkbin = ZkBinary::decode(&zkbin).unwrap();
|
||||
let zkbin = ZkBinary::decode(&zkbin, false).unwrap();
|
||||
|
||||
// Construct the circuit to be able to read the VerifyingKey
|
||||
let circuit = ZkCircuit::new(empty_witnesses(&zkbin).unwrap(), &zkbin);
|
||||
|
||||
@@ -266,7 +266,7 @@ impl TestHarness {
|
||||
let mut proving_keys = HashMap::new();
|
||||
for (bincode, namespace, pk) in pks {
|
||||
let mut reader = Cursor::new(pk);
|
||||
let zkbin = ZkBinary::decode(&bincode)?;
|
||||
let zkbin = ZkBinary::decode(&bincode, false)?;
|
||||
let circuit = ZkCircuit::new(empty_witnesses(&zkbin)?, &zkbin);
|
||||
let proving_key = ProvingKey::read(&mut reader, circuit)?;
|
||||
proving_keys.insert(namespace, (proving_key, zkbin));
|
||||
|
||||
@@ -143,7 +143,7 @@ pub fn get_cached_pks_and_vks() -> Result<(Pks, Vks)> {
|
||||
let mut vks = vec![];
|
||||
|
||||
for bincode in bins.iter() {
|
||||
let zkbin = ZkBinary::decode(bincode)?;
|
||||
let zkbin = ZkBinary::decode(bincode, false)?;
|
||||
debug!("Building PK for {}", zkbin.namespace);
|
||||
let witnesses = empty_witnesses(&zkbin)?;
|
||||
let circuit = ZkCircuit::new(witnesses, &zkbin);
|
||||
|
||||
@@ -890,7 +890,7 @@ pub(crate) fn zkas_db_set(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, ptr_le
|
||||
};
|
||||
|
||||
// Validate the bytes by decoding them into the ZkBinary format
|
||||
let zkbin = match ZkBinary::decode(&zkbin_bytes) {
|
||||
let zkbin = match ZkBinary::decode(&zkbin_bytes, false) {
|
||||
Ok(zkbin) => zkbin,
|
||||
Err(e) => {
|
||||
error!(
|
||||
|
||||
@@ -67,7 +67,7 @@ impl ZkBinary {
|
||||
analyzer.witnesses,
|
||||
analyzer.statements,
|
||||
analyzer.literals,
|
||||
true,
|
||||
false,
|
||||
);
|
||||
|
||||
let bincode = compiler.compile().unwrap();
|
||||
@@ -77,7 +77,7 @@ impl ZkBinary {
|
||||
|
||||
#[staticmethod]
|
||||
fn decode(bytes: Vec<u8>) -> Self {
|
||||
let bincode = decoder::ZkBinary::decode(bytes.as_slice()).unwrap();
|
||||
let bincode = decoder::ZkBinary::decode(bytes.as_slice(), true).unwrap();
|
||||
Self(bincode)
|
||||
}
|
||||
|
||||
@@ -88,6 +88,18 @@ impl ZkBinary {
|
||||
fn opcodes(&self) -> Vec<ZkOpcode> {
|
||||
self.0.opcodes.iter().map(|op| ZkOpcode(op.0)).collect()
|
||||
}
|
||||
|
||||
fn opcode_location(&self, opcode_idx: usize) -> Option<(usize, usize)> {
|
||||
self.0.opcode_location(opcode_idx)
|
||||
}
|
||||
|
||||
fn heap_name(&self, heap_idx: usize) -> Option<&str> {
|
||||
self.0.heap_name(heap_idx)
|
||||
}
|
||||
|
||||
fn literal_name(&self, literal_idx: usize) -> Option<&str> {
|
||||
self.0.literal_name(literal_idx)
|
||||
}
|
||||
}
|
||||
|
||||
#[pyclass(eq, eq_int)]
|
||||
@@ -285,6 +297,7 @@ impl Proof {
|
||||
literals: Vec::new(),
|
||||
witnesses: Vec::new(),
|
||||
opcodes: Vec::new(),
|
||||
debug_info: None,
|
||||
};
|
||||
let empty_circuit = zk::vm::ZkCircuit::new(Vec::new(), &zkbin);
|
||||
let empty_py_circuit = ZkCircuit(empty_circuit, Vec::new(), zkbin);
|
||||
|
||||
@@ -22,6 +22,9 @@ use darkfi_serial::{serialize, VarInt};
|
||||
|
||||
use super::{
|
||||
ast::{Arg, Constant, Literal, Statement, StatementType, Witness},
|
||||
constants::{
|
||||
SECTION_CIRCUIT, SECTION_CONSTANT, SECTION_DEBUG, SECTION_LITERAL, SECTION_WITNESS,
|
||||
},
|
||||
error::ErrorEmitter,
|
||||
types::HeapType,
|
||||
};
|
||||
@@ -81,7 +84,7 @@ impl Compiler {
|
||||
|
||||
// In the .constant section of the binary, we write the constant's type,
|
||||
// and the name so the VM can look it up from `src/crypto/constants/`.
|
||||
bincode.extend_from_slice(b".constant");
|
||||
bincode.extend_from_slice(SECTION_CONSTANT);
|
||||
for i in &self.constants {
|
||||
tmp_heap.push(i.name.as_str());
|
||||
bincode.push(i.typ as u8);
|
||||
@@ -91,7 +94,7 @@ impl Compiler {
|
||||
// Currently, our literals are only Uint64 types, in the binary we'll
|
||||
// add them here in the .literal section. In the VM, they will be on
|
||||
// their own heap, used for reference by opcodes.
|
||||
bincode.extend_from_slice(b".literal");
|
||||
bincode.extend_from_slice(SECTION_LITERAL);
|
||||
for i in &self.literals {
|
||||
bincode.push(i.typ as u8);
|
||||
bincode.extend_from_slice(&serialize(&i.name));
|
||||
@@ -99,13 +102,13 @@ impl Compiler {
|
||||
|
||||
// In the .witness section, we write all our witness types, on the heap
|
||||
// they're in order of appearance.
|
||||
bincode.extend_from_slice(b".witness");
|
||||
bincode.extend_from_slice(SECTION_WITNESS);
|
||||
for i in &self.witnesses {
|
||||
tmp_heap.push(i.name.as_str());
|
||||
bincode.push(i.typ as u8);
|
||||
}
|
||||
|
||||
bincode.extend_from_slice(b".circuit");
|
||||
bincode.extend_from_slice(SECTION_CIRCUIT);
|
||||
for i in &self.statements {
|
||||
match i.typ {
|
||||
StatementType::Assign => tmp_heap.push(&i.lhs.as_ref().unwrap().name),
|
||||
@@ -155,7 +158,46 @@ impl Compiler {
|
||||
return Ok(bincode)
|
||||
}
|
||||
|
||||
// TODO: Otherwise, we proceed appending debug info.
|
||||
// Otherwise, we proceed appending debug info.
|
||||
bincode.extend_from_slice(SECTION_DEBUG);
|
||||
|
||||
// Write source locations for each opcode.
|
||||
// This allows mapping runtime errors back to source lines.
|
||||
bincode.extend_from_slice(&serialize(&VarInt(self.statements.len() as u64)));
|
||||
for stmt in &self.statements {
|
||||
bincode.extend_from_slice(&serialize(&VarInt(stmt.line as u64)));
|
||||
// For column, use the lhs variable's column if available
|
||||
let column = stmt.lhs.as_ref().map(|v| v.column).unwrap_or(0);
|
||||
bincode.extend_from_slice(&serialize(&VarInt(column as u64)));
|
||||
}
|
||||
|
||||
// Write heap variable names.
|
||||
// The heap contains constants, witnesses, assigned variables (in order).
|
||||
// This allows showing meaningful names instead of heap indices.
|
||||
let heap_size = self.constants.len() +
|
||||
self.witnesses.len() +
|
||||
self.statements.iter().filter(|s| s.typ == StatementType::Assign).count();
|
||||
bincode.extend_from_slice(&serialize(&VarInt(heap_size as u64)));
|
||||
|
||||
for constant in &self.constants {
|
||||
bincode.extend_from_slice(&serialize(&constant.name));
|
||||
}
|
||||
|
||||
for witness in &self.witnesses {
|
||||
bincode.extend_from_slice(&serialize(&witness.name));
|
||||
}
|
||||
|
||||
for stmt in &self.statements {
|
||||
if stmt.typ == StatementType::Assign {
|
||||
bincode.extend_from_slice(&serialize(&stmt.lhs.as_ref().unwrap().name));
|
||||
}
|
||||
}
|
||||
|
||||
// Write literal names (the literal values as strings, e.g. "42")
|
||||
bincode.extend_from_slice(&serialize(&VarInt(self.literals.len() as u64)));
|
||||
for literal in &self.literals {
|
||||
bincode.extend_from_slice(&serialize(&literal.name));
|
||||
}
|
||||
|
||||
Ok(bincode)
|
||||
}
|
||||
|
||||
@@ -33,3 +33,10 @@ pub const ALLOWED_FIELDS: [&str; 1] = ["pallas"];
|
||||
|
||||
/// Maximum recursion depth for nested function calls
|
||||
pub const MAX_RECURSION_DEPTH: usize = 16;
|
||||
|
||||
// Section markers in the binary format
|
||||
pub(super) const SECTION_CONSTANT: &[u8] = b".constant";
|
||||
pub(super) const SECTION_LITERAL: &[u8] = b".literal";
|
||||
pub(super) const SECTION_WITNESS: &[u8] = b".witness";
|
||||
pub(super) const SECTION_CIRCUIT: &[u8] = b".circuit";
|
||||
pub(super) const SECTION_DEBUG: &[u8] = b".debug";
|
||||
|
||||
@@ -20,23 +20,19 @@ use darkfi_serial::{deserialize_partial, VarInt};
|
||||
|
||||
use super::{
|
||||
compiler::MAGIC_BYTES,
|
||||
constants::{MAX_K, MAX_NS_LEN, MIN_BIN_SIZE},
|
||||
constants::{
|
||||
MAX_K, MAX_NS_LEN, MIN_BIN_SIZE, SECTION_CIRCUIT, SECTION_CONSTANT, SECTION_DEBUG,
|
||||
SECTION_LITERAL, SECTION_WITNESS,
|
||||
},
|
||||
types::HeapType,
|
||||
LitType, Opcode, VarType,
|
||||
};
|
||||
use crate::{Error::ZkasDecoderError as ZkasErr, Result};
|
||||
|
||||
// Section markers in the binary format
|
||||
const SECTION_CONSTANT: &[u8] = b".constant";
|
||||
const SECTION_LITERAL: &[u8] = b".literal";
|
||||
const SECTION_WITNESS: &[u8] = b".witness";
|
||||
const SECTION_CIRCUIT: &[u8] = b".circuit";
|
||||
const SECTION_DEBUG: &[u8] = b".debug";
|
||||
|
||||
/// A ZkBinary decoded from compiled zkas code.
|
||||
/// This is used by the zkvm.
|
||||
///
|
||||
/// The binary format consits of:
|
||||
/// The binary format consists of:
|
||||
/// - Header: magic bytes, version, k param, namespace
|
||||
/// - `.constant` section: constant types and names
|
||||
/// - `.literal` section: literal types and values
|
||||
@@ -52,9 +48,22 @@ pub struct ZkBinary {
|
||||
pub literals: Vec<(LitType, String)>,
|
||||
pub witnesses: Vec<VarType>,
|
||||
pub opcodes: Vec<(Opcode, Vec<(HeapType, usize)>)>,
|
||||
pub debug_info: Option<DebugInfo>,
|
||||
}
|
||||
// ANCHOR_END: zkbinary-struct
|
||||
|
||||
/// Debug information decoded from the optional .debug section
|
||||
/// Contains source mappings to help debug circuit failures.
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct DebugInfo {
|
||||
/// Source locations (line, col) for each opcode
|
||||
pub opcode_locations: Vec<(usize, usize)>,
|
||||
/// Variable names for each heap entry (constants, witnesses, assigned vars in order)
|
||||
pub heap_names: Vec<String>,
|
||||
/// Literal values as strings
|
||||
pub literal_names: Vec<String>,
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/questions/35901547/how-can-i-find-a-subsequence-in-a-u8-slice
|
||||
fn find_subslice(haystack: &[u8], needle: &[u8]) -> Option<usize> {
|
||||
haystack.windows(needle.len()).position(|window| window == needle)
|
||||
@@ -125,11 +134,20 @@ impl SectionOffsets {
|
||||
fn circuit_bytes<'a>(&self, bytes: &'a [u8]) -> &'a [u8] {
|
||||
&bytes[self.circuit + SECTION_CIRCUIT.len()..self.debug]
|
||||
}
|
||||
|
||||
/// Extract the bytes for the debug section if present
|
||||
fn debug_bytes<'a>(&self, bytes: &'a [u8]) -> Option<&'a [u8]> {
|
||||
if self.debug < bytes.len() {
|
||||
Some(&bytes[self.debug + SECTION_DEBUG.len()..])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ZkBinary {
|
||||
/// Decode a ZkBinary from compiled bytes
|
||||
pub fn decode(bytes: &[u8]) -> Result<Self> {
|
||||
pub fn decode(bytes: &[u8], decode_debug_symbols: bool) -> Result<Self> {
|
||||
// Ensure that bytes is a certain minimum length. Otherwise the code
|
||||
// below will panic due to an index out of bounds error.
|
||||
if bytes.len() < MIN_BIN_SIZE {
|
||||
@@ -168,9 +186,15 @@ impl ZkBinary {
|
||||
let witnesses = Self::parse_witnesses(offsets.witness_bytes(bytes))?;
|
||||
let opcodes = Self::parse_circuit(offsets.circuit_bytes(bytes))?;
|
||||
|
||||
// TODO: Debug info
|
||||
let mut debug_info = None;
|
||||
if decode_debug_symbols {
|
||||
debug_info = match offsets.debug_bytes(bytes) {
|
||||
Some(debug_bytes) => Some(Self::parse_debug(debug_bytes)?),
|
||||
None => None,
|
||||
};
|
||||
}
|
||||
|
||||
Ok(Self { namespace, k, constants, literals, witnesses, opcodes })
|
||||
Ok(Self { namespace, k, constants, literals, witnesses, opcodes, debug_info })
|
||||
}
|
||||
|
||||
fn parse_constants(bytes: &[u8]) -> Result<Vec<(VarType, String)>> {
|
||||
@@ -280,6 +304,70 @@ impl ZkBinary {
|
||||
|
||||
Ok(opcodes)
|
||||
}
|
||||
|
||||
fn parse_debug(bytes: &[u8]) -> Result<DebugInfo> {
|
||||
let mut offset = 0;
|
||||
|
||||
// Parse opcode source locations
|
||||
let (num_opcodes, len) = deserialize_partial::<VarInt>(&bytes[offset..])?;
|
||||
offset += len;
|
||||
|
||||
let mut opcode_locations = Vec::with_capacity(num_opcodes.0 as usize);
|
||||
for _ in 0..num_opcodes.0 {
|
||||
let (line, len) = deserialize_partial::<VarInt>(&bytes[offset..])?;
|
||||
offset += len;
|
||||
let (column, len) = deserialize_partial::<VarInt>(&bytes[offset..])?;
|
||||
offset += len;
|
||||
opcode_locations.push((line.0 as usize, column.0 as usize));
|
||||
}
|
||||
|
||||
// Parse heap var names
|
||||
let (heap_size, len) = deserialize_partial::<VarInt>(&bytes[offset..])?;
|
||||
offset += len;
|
||||
|
||||
let mut heap_names = Vec::with_capacity(heap_size.0 as usize);
|
||||
for _ in 0..heap_size.0 {
|
||||
let (name, len) = deserialize_partial::<String>(&bytes[offset..])?;
|
||||
offset += len;
|
||||
heap_names.push(name);
|
||||
}
|
||||
|
||||
// Parse literal names
|
||||
let (num_literals, len) = deserialize_partial::<VarInt>(&bytes[offset..])?;
|
||||
offset += len;
|
||||
|
||||
let mut literal_names = Vec::with_capacity(num_literals.0 as usize);
|
||||
for _ in 0..num_literals.0 {
|
||||
let (name, len) = deserialize_partial::<String>(&bytes[offset..])?;
|
||||
offset += len;
|
||||
literal_names.push(name);
|
||||
}
|
||||
|
||||
Ok(DebugInfo { opcode_locations, heap_names, literal_names })
|
||||
}
|
||||
|
||||
/// Get the source location (line, column) for a given opcode index.
|
||||
/// Returns `None` if debug info is not present or index is OOB.
|
||||
pub fn opcode_location(&self, opcode_idx: usize) -> Option<(usize, usize)> {
|
||||
self.debug_info.as_ref()?.opcode_locations.get(opcode_idx).copied()
|
||||
}
|
||||
|
||||
/// Get the variable name for a given heap index.
|
||||
/// Returns `None` if debug info is not present or index is OOB.
|
||||
pub fn heap_name(&self, heap_idx: usize) -> Option<&str> {
|
||||
self.debug_info.as_ref()?.heap_names.get(heap_idx).map(|s| s.as_str())
|
||||
}
|
||||
|
||||
/// Get the literal name/value for a given literal index.
|
||||
/// Returns `None` if debug info is not present or index is OOB.
|
||||
pub fn literal_name(&self, literal_idx: usize) -> Option<&str> {
|
||||
self.debug_info.as_ref()?.literal_names.get(literal_idx).map(|s| s.as_str())
|
||||
}
|
||||
|
||||
/// Check if debug info is present
|
||||
pub fn has_debug_info(&self) -> bool {
|
||||
self.debug_info.is_some()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -291,7 +379,7 @@ mod tests {
|
||||
// Out-of-memory panic from string deserialization.
|
||||
// Read `doc/src/zkas/bincode.md` to understand the input.
|
||||
let data = vec![11u8, 1, 177, 53, 1, 0, 0, 0, 0, 255, 0, 204, 200, 72, 72, 72, 72, 1];
|
||||
let _dec = ZkBinary::decode(&data);
|
||||
let _dec = ZkBinary::decode(&data, true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -307,6 +395,6 @@ mod tests {
|
||||
116, 4, 2, 0, 2, 0, 0, 2, 2, 0, 3, 0, 1, 8, 2, 0, 4, 0, 5, 8, 1, 0, 6, 9, 1, 0, 6, 240,
|
||||
1, 0, 7, 240, 41, 0, 0, 0, 1, 0, 8,
|
||||
];
|
||||
let _dec = ZkBinary::decode(&data);
|
||||
let _dec = ZkBinary::decode(&data, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ use darkfi::{
|
||||
#[test]
|
||||
fn halo2_vk_ser() -> Result<()> {
|
||||
let bincode = include_bytes!("../proof/opcodes.zk.bin");
|
||||
let zkbin = ZkBinary::decode(bincode)?;
|
||||
let zkbin = ZkBinary::decode(bincode, false)?;
|
||||
|
||||
let verifier_witnesses = empty_witnesses(&zkbin)?;
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ use darkfi::{
|
||||
#[test]
|
||||
fn zkvm_smt() -> Result<()> {
|
||||
let bincode = include_bytes!("../proof/smt.zk.bin");
|
||||
let zkbin = ZkBinary::decode(bincode)?;
|
||||
let zkbin = ZkBinary::decode(bincode, false)?;
|
||||
|
||||
let hasher = PoseidonFp::new();
|
||||
let store = MemoryStorageFp::new();
|
||||
|
||||
@@ -46,7 +46,7 @@ use darkfi::{
|
||||
#[test]
|
||||
fn zkvm_opcodes() -> Result<()> {
|
||||
let bincode = include_bytes!("../proof/opcodes.zk.bin");
|
||||
let zkbin = ZkBinary::decode(bincode)?;
|
||||
let zkbin = ZkBinary::decode(bincode, false)?;
|
||||
|
||||
// Values for the proof
|
||||
let value = 666_u64;
|
||||
|
||||
Reference in New Issue
Block a user