Skip to content

Commit 187280f

Browse files
authored
Merge pull request #33 from anoma/xuyang/refactor_architecture
architecture refactor
2 parents 0e5dd1a + ccaff17 commit 187280f

29 files changed

+566
-540
lines changed

Diff for: bench/compliance_circuit_bench.exs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
{:ok, program} = File.read("./native/cairo_vm/compliance.json")
2-
{:ok, input} = File.read("./native/cairo_vm/compliance_input.json")
1+
{:ok, program} = File.read("./juvix/compliance.json")
2+
{:ok, input} = File.read("./juvix/compliance_input.json")
33

44
{_output, trace, memory, public_inputs} =
55
Cairo.cairo_vm_runner(

Diff for: bench/logic_circuit_bench.exs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
{:ok, program} = File.read("./native/cairo_vm/trivial_resource_logic.json")
1+
{:ok, program} = File.read("./juvix/trivial_resource_logic.json")
22

33
{:ok, input} =
4-
File.read("./native/cairo_vm/trivial_resource_logic_input.json")
4+
File.read("./juvix/trivial_resource_logic_input.json")
55

66
{_output, trace, memory, public_inputs} =
77
Cairo.cairo_vm_runner(
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

Diff for: native/cairo_prover/src/binding_signature.rs

+117
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
use crate::{
2+
error::CairoError,
3+
utils::{bytes_to_affine, bytes_to_felt, bytes_to_felt_vec},
4+
};
5+
use num_bigint::BigInt;
6+
use num_integer::Integer;
7+
use num_traits::Zero;
8+
use rand::{thread_rng, RngCore};
9+
use rustler::NifResult;
10+
use starknet_crypto::{poseidon_hash_many, sign, verify};
11+
use starknet_curve::curve_params::{EC_ORDER, GENERATOR};
12+
use starknet_types_core::{curve::ProjectivePoint, felt::Felt};
13+
use std::ops::Add;
14+
15+
// The private_key_segments are random values used in delta commitments.
16+
// The messages are nullifiers and resource commitments in the transaction.
17+
#[rustler::nif]
18+
fn cairo_binding_sig_sign(
19+
private_key_segments: Vec<u8>,
20+
messages: Vec<Vec<u8>>,
21+
) -> NifResult<Vec<u8>> {
22+
if private_key_segments.is_empty() || private_key_segments.len() % 32 != 0 {
23+
return Err(CairoError::InvalidInputs.into());
24+
}
25+
// Compute private key
26+
let private_key = {
27+
let result = private_key_segments
28+
.chunks(32)
29+
.fold(BigInt::zero(), |acc, key_segment| {
30+
let key = BigInt::from_bytes_be(num_bigint::Sign::Plus, key_segment);
31+
acc.add(key)
32+
})
33+
.mod_floor(&EC_ORDER.to_bigint());
34+
35+
let (_, buffer) = result.to_bytes_be();
36+
let mut result = [0u8; 32];
37+
result[(32 - buffer.len())..].copy_from_slice(&buffer[..]);
38+
39+
Felt::from_bytes_be(&result)
40+
};
41+
42+
// Message digest
43+
let sig_hash = message_digest(messages)?;
44+
45+
// ECDSA sign
46+
let mut rng = thread_rng();
47+
let k = {
48+
let mut felt: [u8; 32] = Default::default();
49+
rng.fill_bytes(&mut felt);
50+
Felt::from_bytes_be(&felt)
51+
};
52+
let signature = sign(&private_key, &sig_hash, &k).map_err(CairoError::from)?;
53+
54+
// Serialize signature
55+
let mut ret = Vec::new();
56+
ret.extend(signature.r.to_bytes_be());
57+
ret.extend(signature.s.to_bytes_be());
58+
// We don't need the v to recover pubkey
59+
// ret.extend(signature.v.to_bytes_be());
60+
Ok(ret)
61+
}
62+
63+
// The pub_key_segments are delta commitments in compliance input inputs.
64+
#[rustler::nif]
65+
fn cairo_binding_sig_verify(
66+
pub_key_segments: Vec<Vec<u8>>,
67+
messages: Vec<Vec<u8>>,
68+
signature: Vec<u8>,
69+
) -> NifResult<bool> {
70+
// Generate the public key
71+
let mut pub_key = ProjectivePoint::identity();
72+
for pk_seg_bytes in pub_key_segments.into_iter() {
73+
let pk_seg = bytes_to_affine(pk_seg_bytes)?;
74+
pub_key += pk_seg;
75+
}
76+
let pub_key_x = pub_key
77+
.to_affine()
78+
.map_err(|_| CairoError::InvalidAffinePoint)?
79+
.x();
80+
81+
// Message digest
82+
let msg = message_digest(messages)?;
83+
84+
// Decode the signature
85+
if signature.len() != 64 {
86+
return Err(CairoError::InvalidSignatureFormat.into());
87+
}
88+
89+
let (r_bytes, s_bytes) = signature.split_at(32);
90+
let r = bytes_to_felt(r_bytes.to_vec())?;
91+
let s = bytes_to_felt(s_bytes.to_vec())?;
92+
93+
// Verify the signature
94+
verify(&pub_key_x, &msg, &r, &s).map_err(|_| CairoError::SigVerifyError.into())
95+
}
96+
97+
#[rustler::nif]
98+
fn get_public_key(priv_key: Vec<u8>) -> NifResult<Vec<u8>> {
99+
let priv_key_felt = bytes_to_felt(priv_key)?;
100+
101+
let generator = ProjectivePoint::from_affine(GENERATOR.x(), GENERATOR.y())
102+
.map_err(|_| CairoError::InvalidAffinePoint)?;
103+
104+
let pub_key = (&generator * priv_key_felt)
105+
.to_affine()
106+
.map_err(|_| CairoError::InvalidAffinePoint)?;
107+
108+
let mut ret = pub_key.x().to_bytes_be().to_vec();
109+
let mut y = pub_key.y().to_bytes_be().to_vec();
110+
ret.append(&mut y);
111+
Ok(ret)
112+
}
113+
114+
fn message_digest(msg: Vec<Vec<u8>>) -> NifResult<Felt> {
115+
let felt_msg_vec: Vec<Felt> = bytes_to_felt_vec(msg)?;
116+
Ok(poseidon_hash_many(&felt_msg_vec))
117+
}

Diff for: native/cairo_prover/src/compliance_input.rs

+34
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,28 @@
11
use crate::{error::CairoError, utils::felt_to_string};
2+
use rustler::NifResult;
23
use serde::{Deserialize, Serialize};
34

5+
#[rustler::nif]
6+
fn cairo_generate_compliance_input_json(
7+
input_resource: Vec<u8>,
8+
output_resource: Vec<u8>,
9+
path: Vec<Vec<u8>>,
10+
pos: u64,
11+
input_nf_key: Vec<u8>,
12+
eph_root: Vec<u8>,
13+
rcv: Vec<u8>,
14+
) -> NifResult<String> {
15+
Ok(ComplianceInputJson::to_json_string(
16+
input_resource,
17+
output_resource,
18+
path,
19+
pos,
20+
input_nf_key,
21+
eph_root,
22+
rcv,
23+
)?)
24+
}
25+
426
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
527
pub struct ComplianceInputJson {
628
input: ResourceJson,
@@ -108,3 +130,15 @@ fn test_compliance_input_json() {
108130

109131
println!("compliance_input_json: {}", json);
110132
}
133+
134+
#[test]
135+
fn generate_compliance_input_test_params() {
136+
use starknet_crypto::poseidon_hash;
137+
use starknet_types_core::felt::Felt;
138+
139+
println!("Felf one hex: {:?}", Felt::ONE.to_hex_string());
140+
let input_nf_key = Felt::ONE;
141+
let input_npk = poseidon_hash(input_nf_key, Felt::ZERO);
142+
println!("input_npk: {:?}", input_npk.to_bytes_be());
143+
println!("input_npk: {:?}", input_npk.to_hex_string());
144+
}

Diff for: native/cairo_prover/src/constants.rs

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
use lazy_static::lazy_static;
2+
3+
// The PLAINTEXT_NUM should be fixed to achieve the indistinguishability of resource logics
4+
// Make it 10
5+
pub const PLAINTEXT_NUM: usize = 10;
6+
pub const CIPHERTEXT_MAC: usize = PLAINTEXT_NUM;
7+
pub const CIPHERTEXT_PK_X: usize = PLAINTEXT_NUM + 1;
8+
pub const CIPHERTEXT_PK_Y: usize = PLAINTEXT_NUM + 2;
9+
pub const CIPHERTEXT_NONCE: usize = PLAINTEXT_NUM + 3;
10+
pub const CIPHERTEXT_NUM: usize = PLAINTEXT_NUM + 4;
11+
12+
lazy_static! {
13+
// Bytes: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 97, 105, 114, 111, 95, 69, 120, 112, 97, 110, 100, 83, 101, 101, 100]
14+
// Hexstring: "0x436169726f5f457870616e6453656564"
15+
// Decimal string(used in juvix): "89564067232354163924078705540990330212"
16+
pub static ref PRF_EXPAND_PERSONALIZATION_FELT: Vec<u8> = {
17+
let personalization: Vec<u8> = b"Cairo_ExpandSeed".to_vec();
18+
let mut result = [0u8; 32];
19+
result[(32 - personalization.len())..].copy_from_slice(&personalization[..]);
20+
21+
result.to_vec()
22+
};
23+
}
24+
25+
#[test]
26+
fn test_prf_expand_personalization() {
27+
use starknet_types_core::felt::Felt;
28+
println!(
29+
"PRF_EXPAND_PERSONALIZATION_FELT bytes: {:?}",
30+
*PRF_EXPAND_PERSONALIZATION_FELT
31+
);
32+
33+
println!(
34+
"hex: {:?}",
35+
Felt::from_bytes_be(
36+
&PRF_EXPAND_PERSONALIZATION_FELT
37+
.as_slice()
38+
.try_into()
39+
.unwrap()
40+
)
41+
.to_hex_string()
42+
);
43+
}

Diff for: native/cairo_prover/src/encryption.rs

+54-14
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,63 @@
1-
use crate::{error::CairoError, utils::bytes_to_felt_vec};
1+
use crate::{
2+
constants::{
3+
CIPHERTEXT_MAC, CIPHERTEXT_NONCE, CIPHERTEXT_NUM, CIPHERTEXT_PK_X, CIPHERTEXT_PK_Y,
4+
PLAINTEXT_NUM,
5+
},
6+
error::CairoError,
7+
utils::{bytes_to_affine, bytes_to_felt, bytes_to_felt_vec},
8+
};
9+
use rustler::NifResult;
210
use starknet_crypto::{poseidon_hash, poseidon_hash_many};
311
use starknet_curve::curve_params::GENERATOR;
412
use starknet_types_core::{
513
curve::{AffinePoint, ProjectivePoint},
614
felt::Felt,
715
};
816

9-
// The PLAINTEXT_NUM should be fixed to achieve the indistinguishability of resource logics
10-
// Make it 10
11-
pub const PLAINTEXT_NUM: usize = 10;
12-
pub const CIPHERTEXT_MAC: usize = PLAINTEXT_NUM;
13-
pub const CIPHERTEXT_PK_X: usize = PLAINTEXT_NUM + 1;
14-
pub const CIPHERTEXT_PK_Y: usize = PLAINTEXT_NUM + 2;
15-
pub const CIPHERTEXT_NONCE: usize = PLAINTEXT_NUM + 3;
16-
pub const CIPHERTEXT_NUM: usize = PLAINTEXT_NUM + 4;
17+
#[rustler::nif]
18+
fn encrypt(
19+
messages: Vec<Vec<u8>>,
20+
pk: Vec<u8>,
21+
sk: Vec<u8>,
22+
nonce: Vec<u8>,
23+
) -> NifResult<Vec<Vec<u8>>> {
24+
// Decode messages
25+
let msgs_felt = bytes_to_felt_vec(messages)?;
26+
27+
// Decode pk
28+
let pk_affine = bytes_to_affine(pk)?;
29+
30+
// Decode sk
31+
let sk_felt = bytes_to_felt(sk)?;
32+
33+
// Decode nonce
34+
let nonce_felt = bytes_to_felt(nonce)?;
35+
36+
// Encrypt
37+
let cipher = Ciphertext::encrypt(&msgs_felt, &pk_affine, &sk_felt, &nonce_felt)?;
38+
let cipher_bytes = cipher
39+
.inner()
40+
.iter()
41+
.map(|x| x.to_bytes_be().to_vec())
42+
.collect();
43+
44+
Ok(cipher_bytes)
45+
}
46+
47+
#[rustler::nif]
48+
fn decrypt(cihper: Vec<Vec<u8>>, sk: Vec<u8>) -> NifResult<Vec<Vec<u8>>> {
49+
// Decode messages
50+
let cipher = Ciphertext::from_bytes(cihper)?;
51+
52+
// Decode sk
53+
let sk_felt = bytes_to_felt(sk)?;
54+
55+
// Encrypt
56+
let plaintext = cipher.decrypt(&sk_felt)?;
57+
let plaintext_bytes = plaintext.iter().map(|x| x.to_bytes_be().to_vec()).collect();
58+
59+
Ok(plaintext_bytes)
60+
}
1761

1862
#[derive(Debug, Clone)]
1963
pub struct Ciphertext([Felt; CIPHERTEXT_NUM]);
@@ -132,10 +176,6 @@ impl Plaintext {
132176
&self.0
133177
}
134178

135-
pub fn to_vec(&self) -> Vec<Felt> {
136-
self.0.to_vec()
137-
}
138-
139179
pub fn padding(msg: &[Felt]) -> Self {
140180
let mut plaintext = msg.to_owned();
141181
let padding = std::iter::repeat(Felt::ZERO).take(PLAINTEXT_NUM - msg.len());
@@ -186,5 +226,5 @@ fn test_encryption() {
186226
let decryption = cipher.decrypt(&Felt::ONE).unwrap();
187227

188228
let padded_plaintext = Plaintext::padding(&messages);
189-
assert_eq!(padded_plaintext.to_vec(), decryption);
229+
assert_eq!(padded_plaintext.inner().to_vec(), decryption);
190230
}

0 commit comments

Comments
 (0)