Skip to content

Commit

Permalink
Merge branch 'plume-sig:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
RajeshRk18 authored Dec 9, 2023
2 parents cc9afb0 + 42789dc commit bd2e48e
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 78 deletions.
5 changes: 1 addition & 4 deletions circuits/circom/test/sha256Circuit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,7 @@ describe("SHA256 Circuit", () => {
const p = path.join(__dirname, "./circuits/12_point_sha_256_test.circom");
const circuit = await wasm_tester(p, { json: true, sym: true });

const w = await circuit.calculateWitness(
{ coordinates, preimage_bit_length: v1_sha256_preimage_bit_length },
true,
);
const w = await circuit.calculateWitness({ coordinates }, true);
await circuit.checkConstraints(w);
await circuit.assertOut(w, { out: v1_binary_c });
});
Expand Down
1 change: 0 additions & 1 deletion circuits/circom/test/v1.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ describe("V1 Circuit", () => {
pk: pointToCircuitValue(Point.fromPrivateKey(testSecretKey)),
nullifier: pointToCircuitValue(nullifier),
...htci,
sha256_preimage_bit_length: v1_sha256_preimage_bit_length,
});
await circuit.checkConstraints(w);
});
Expand Down
15 changes: 8 additions & 7 deletions circuits/circom/verify_nullifier.circom
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ include "./node_modules/circom-ecdsa/circuits/secp256k1_func.circom";
include "./node_modules/secp256k1_hash_to_curve_circom/circom/hash_to_curve.circom";
include "./node_modules/secp256k1_hash_to_curve_circom/circom/Sha256.circom";
include "./node_modules/circomlib/circuits/bitify.circom";
include "./node_modules/circomlib/circuits/comparators.circom";

// Verifies that a nullifier belongs to a specific public key \
// This blog explains the intuition behind the construction https://blog.aayushg.com/posts/nullifier
Expand All @@ -29,9 +30,6 @@ template plume_v1(n, k, message_length) {
signal input q1_x_mapped[4];
signal input q1_y_mapped[4];

// precomputed value for the sha256 component. TODO: calculate internally in circom to simplify API
signal input sha256_preimage_bit_length;

component check_ec_equations = check_ec_equations(n, k, message_length);

check_ec_equations.c <== c;
Expand All @@ -58,7 +56,6 @@ template plume_v1(n, k, message_length) {
var g[2][100];
g[0] = get_genx(n, k);
g[1] = get_geny(n, k);
c_sha256.preimage_bit_length <== sha256_preimage_bit_length;

for (var i = 0; i < 2; i++) {
for (var j = 0; j < k; j++) {
Expand Down Expand Up @@ -259,7 +256,6 @@ template a_div_b_pow_c(n, k) {

template sha256_12_coordinates(n, k) {
signal input coordinates[12][k];
signal input preimage_bit_length;
signal output out[256];

// compress coordinates
Expand Down Expand Up @@ -305,13 +301,18 @@ template sha256_12_coordinates(n, k) {
sha256.padded_bits[i] <== sha256.msg[i];
}
}

component bit_length_binary = Num2Bits(64);
bit_length_binary.in <== preimage_bit_length;
bit_length_binary.in <== message_bits;
for (var i = 0; i < 64; i++) {
sha256.padded_bits[total_bits - i - 1] <== bit_length_binary.out[i];
}

// feels like a needed check as `Num2Bits.in` doesn't participate in a quadratic constraint
component preimage_bit_length_check = ForceEqualIfEnabled();
preimage_bit_length_check.enabled <== 1;
preimage_bit_length_check.in <== [message_bits, bit_length_binary.in];

out <== sha256.out;
}

Expand Down
10 changes: 1 addition & 9 deletions rust-k256/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,12 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
crate = "0.0.2"
# ring = "0.16.20"
rand_core = "0.6.3"
hex-literal = "0.3.4"
hash2field = "0.4.0"
num-bigint = "0.4.3"
num-integer = "0.1.45"
k256 = { version = "0.11.3", features = [
"arithmetic",
"hash2curve",
"expose-field",
"sha2",
] }
elliptic-curve = { version = "0.12.2", features = ["arithmetic"] }
k256 = {version = "0.13.2", features = ["arithmetic", "hash2curve", "expose-field", "sha2"]}

[dev-dependencies]
hex = "0.4.3"
97 changes: 40 additions & 57 deletions rust-k256/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,39 +1,29 @@
// #![feature(generic_const_expr)]
// #![allow(incomplete_features)]

use elliptic_curve::bigint::ArrayEncoding;
use elliptic_curve::hash2curve::{ExpandMsgXmd, GroupDigest};
use elliptic_curve::ops::Reduce;
use elliptic_curve::sec1::ToEncodedPoint;
use k256::{
// ecdsa::{signature::Signer, Signature, SigningKey},
elliptic_curve::group::ff::PrimeField,
elliptic_curve::hash2curve::{ExpandMsgXmd, GroupDigest},
elliptic_curve::ops::ReduceNonZero,
elliptic_curve::sec1::ToEncodedPoint,
elliptic_curve::{bigint::ArrayEncoding, group::ff::PrimeField},
sha2::{digest::Output, Digest, Sha256},
FieldBytes,
ProjectivePoint,
Scalar,
Secp256k1,
U256,
FieldBytes, ProjectivePoint, Scalar, Secp256k1, U256,
}; // requires 'getrandom' feature
use std::panic;

const L: usize = 48;
const COUNT: usize = 2;
const OUT: usize = L * COUNT;
const DST: &[u8] = b"QUUX-V01-CS02-with-secp256k1_XMD:SHA-256_SSWU_RO_"; // Hash to curve algorithm

#[derive(Debug, PartialEq)]
pub enum Error {
IsPointAtInfinityError,
}

fn print_type_of<T>(_: &T) {
println!("{}", std::any::type_name::<T>());
}

fn c_sha256_vec_signal(values: Vec<&ProjectivePoint>) -> Output<Sha256> {
let preimage_vec = values
.into_iter()
.map(|value| encode_pt(value).unwrap())
.map(encode_pt)
.collect::<Vec<_>>()
.concat();
let mut sha256_hasher = Sha256::new();
Expand All @@ -49,12 +39,12 @@ fn sha256hash6signals(
g_r: &ProjectivePoint,
hash_m_pk_pow_r: &ProjectivePoint,
) -> Scalar {
let g_bytes = encode_pt(g).unwrap();
let pk_bytes = encode_pt(pk).unwrap();
let h_bytes = encode_pt(hash_m_pk).unwrap();
let nul_bytes = encode_pt(nullifier).unwrap();
let g_r_bytes = encode_pt(g_r).unwrap();
let z_bytes = encode_pt(hash_m_pk_pow_r).unwrap();
let g_bytes = encode_pt(g);
let pk_bytes = encode_pt(pk);
let h_bytes = encode_pt(hash_m_pk);
let nul_bytes = encode_pt(nullifier);
let g_r_bytes = encode_pt(g_r);
let z_bytes = encode_pt(hash_m_pk_pow_r);

let c_preimage_vec = [g_bytes, pk_bytes, h_bytes, nul_bytes, g_r_bytes, z_bytes].concat();

Expand All @@ -69,14 +59,12 @@ fn sha256hash6signals(
}

// Hashes two values to the curve
fn hash_to_curve(m: &[u8], pk: &ProjectivePoint) -> ProjectivePoint {
let pt: ProjectivePoint = Secp256k1::hash_from_bytes::<ExpandMsgXmd<Sha256>>(
&[[m, &encode_pt(pk).unwrap()].concat().as_slice()],
fn hash_to_curve(m: &[u8], pk: &ProjectivePoint) -> Result<ProjectivePoint, k256::elliptic_curve::Error> {
Secp256k1::hash_from_bytes::<ExpandMsgXmd<Sha256>>(
&[[m, &encode_pt(pk)].concat().as_slice()],
//b"CURVE_XMD:SHA-256_SSWU_RO_",
DST,
&[DST],
)
.unwrap();
pt
}

/* currently seems to right place for this `struct` declaration;
Expand All @@ -96,35 +84,29 @@ pub struct PlumeSignatureV1Fields<'a> {
pub hashed_to_curve_r: &'a ProjectivePoint,
}
impl PlumeSignature<'_> {
/// WARNING: panics when `self.c` isn't an `Output::<Sha256>`.
/// So catch it if it's a possible case for you.
// Verifier check in SNARK:
// g^[r + sk * c] / (g^sk)^c = g^r
// hash[m, gsk]^[r + sk * c] / (hash[m, pk]^sk)^c = hash[m, pk]^r
// c = hash2(g, g^sk, hash[m, g^sk], hash[m, pk]^sk, gr, hash[m, pk]^r)
pub fn verify_signals(&self) -> bool {
// don't forget to check `c` is `Output<Sha256>` in the #API
let c = Output::<Sha256>::from_slice(self.c);
let c = panic::catch_unwind(|| {Output::<Sha256>::from_slice(self.c)});
if c.is_err() {return false;}
let c = c.unwrap();

// TODO should we allow `c` input greater than BaseField::MODULUS?
let c_scalar = &Scalar::from_uint_reduced(U256::from_be_byte_array(c.to_owned()));
/* @skaunov would be glad to discuss with @Divide-By-0 excessive of the following check.
Though I should notice that it at least doesn't breaking anything. */
if c_scalar.is_zero().into() {
// TODO `reduce_nonzero` doesn't seems to be correct here. `NonZeroScalar` should be appropriate.
let c_scalar = &Scalar::reduce_nonzero(U256::from_be_byte_array(c.to_owned()));

let r_point = ProjectivePoint::GENERATOR * self.s - self.pk * c_scalar;

let hashed_to_curve = hash_to_curve(self.message, self.pk);
if hashed_to_curve.is_err() {
return false;
}
let hashed_to_curve = hashed_to_curve.unwrap();

let r_point = ProjectivePoint::GENERATOR * self.s - self.pk * &c_scalar;
let hashed_to_curve = hash_to_curve(self.message, self.pk);
let hashed_to_curve_r = &hashed_to_curve * self.s - self.nullifier * &c_scalar;

// Check if the given hash matches
let result = |components: Vec<&ProjectivePoint>| -> bool {
if &c_sha256_vec_signal(components) == c {
true
} else {
false
}
};
let hashed_to_curve_r = hashed_to_curve * self.s - self.nullifier * c_scalar;

if let Some(PlumeSignatureV1Fields {
r_point: sig_r_point,
Expand All @@ -141,7 +123,8 @@ impl PlumeSignature<'_> {
return false;
}

result(vec![
// Check if the given hash matches
c == &c_sha256_vec_signal(vec![
&ProjectivePoint::GENERATOR,
self.pk,
&hashed_to_curve,
Expand All @@ -150,15 +133,15 @@ impl PlumeSignature<'_> {
&hashed_to_curve_r,
])
} else {
result(vec![self.nullifier, &r_point, &hashed_to_curve_r])
// Check if the given hash matches
c == &c_sha256_vec_signal(vec![self.nullifier, &r_point, &hashed_to_curve_r])
}
}
}

/// Encodes the point by compressing it to 33 bytes
fn encode_pt(point: &ProjectivePoint) -> Result<Vec<u8>, Error> {
let encoded = point.to_encoded_point(true);
Ok(encoded.to_bytes().to_vec())
fn encode_pt(point: &ProjectivePoint) -> Vec<u8> {
point.to_encoded_point(true).to_bytes().to_vec()
}

/// Convert a 32-byte array to a scalar
Expand Down Expand Up @@ -210,7 +193,7 @@ mod tests {
let pt: ProjectivePoint = Secp256k1::hash_from_bytes::<ExpandMsgXmd<Sha256>>(
&[s],
//b"CURVE_XMD:SHA-256_SSWU_RO_"
DST,
&[DST],
)
.unwrap();
pt
Expand Down Expand Up @@ -251,7 +234,7 @@ mod tests {
let g_r = &g * &r;

// hash[m, pk]
let hash_m_pk = hash_to_curve(m, &pk);
let hash_m_pk = hash_to_curve(m, &pk).unwrap();

println!(
"h.x: {:?}",
Expand Down Expand Up @@ -302,7 +285,7 @@ mod tests {
};
dbg!(&c, version);

let c_scalar = &Scalar::from_uint_reduced(U256::from_be_byte_array(c.clone()));
let c_scalar = &Scalar::reduce_nonzero(U256::from_be_byte_array(c.to_owned()));
// This value is part of the discrete log equivalence (DLEQ) proof.
let r_sk_c = r + sk * c_scalar;

Expand Down Expand Up @@ -408,7 +391,7 @@ mod tests {
);

// Test encode_pt()
let g_as_bytes = encode_pt(&g).unwrap();
let g_as_bytes = encode_pt(&g);
assert_eq!(
hex::encode(g_as_bytes),
"0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"
Expand Down

0 comments on commit bd2e48e

Please sign in to comment.