@@ -33,15 +33,35 @@ pub type CommitPED64<N> = CommitInstruction<N, { CommitVariant::CommitPED64 as u
3333/// Pedersen128 is a collision-resistant function that processes inputs in 128-bit chunks.
3434pub type CommitPED128 < N > = CommitInstruction < N , { CommitVariant :: CommitPED128 as u8 } > ;
3535
36+ /// BHP256 commit over raw bits (no type-tagged serialization).
37+ pub type CommitBHP256Raw < N > = CommitInstruction < N , { CommitVariant :: CommitBHP256Raw as u8 } > ;
38+ /// BHP512 commit over raw bits.
39+ pub type CommitBHP512Raw < N > = CommitInstruction < N , { CommitVariant :: CommitBHP512Raw as u8 } > ;
40+ /// BHP768 commit over raw bits.
41+ pub type CommitBHP768Raw < N > = CommitInstruction < N , { CommitVariant :: CommitBHP768Raw as u8 } > ;
42+ /// BHP1024 commit over raw bits.
43+ pub type CommitBHP1024Raw < N > = CommitInstruction < N , { CommitVariant :: CommitBHP1024Raw as u8 } > ;
44+ /// Pedersen64 commit over raw bits.
45+ pub type CommitPED64Raw < N > = CommitInstruction < N , { CommitVariant :: CommitPED64Raw as u8 } > ;
46+ /// Pedersen128 commit over raw bits.
47+ pub type CommitPED128Raw < N > = CommitInstruction < N , { CommitVariant :: CommitPED128Raw as u8 } > ;
48+
3649/// Which commit function to use.
37- #[ derive( Debug , Clone , Eq , PartialEq ) ]
50+ #[ derive( Debug , Copy , Clone , Eq , PartialEq ) ]
3851pub enum CommitVariant {
3952 CommitBHP256 ,
4053 CommitBHP512 ,
4154 CommitBHP768 ,
4255 CommitBHP1024 ,
4356 CommitPED64 ,
4457 CommitPED128 ,
58+ // The variants that commit over raw inputs.
59+ CommitBHP256Raw ,
60+ CommitBHP512Raw ,
61+ CommitBHP768Raw ,
62+ CommitBHP1024Raw ,
63+ CommitPED64Raw ,
64+ CommitPED128Raw ,
4565}
4666
4767impl CommitVariant {
@@ -54,9 +74,21 @@ impl CommitVariant {
5474 3 => "commit.bhp1024" ,
5575 4 => "commit.ped64" ,
5676 5 => "commit.ped128" ,
57- 6 .. => panic ! ( "Invalid 'commit' instruction opcode" ) ,
77+ // The variants that commit over raw inputs.
78+ 6 => "commit.bhp256.raw" ,
79+ 7 => "commit.bhp512.raw" ,
80+ 8 => "commit.bhp768.raw" ,
81+ 9 => "commit.bhp1024.raw" ,
82+ 10 => "commit.ped64.raw" ,
83+ 11 => "commit.ped128.raw" ,
84+ 12 .. => panic ! ( "Invalid 'commit' instruction opcode" ) ,
5885 }
5986 }
87+
88+ // Returns `true` if the variant commits over raw bits.
89+ pub const fn is_raw ( variant : u8 ) -> bool {
90+ matches ! ( variant, 6 ..=11 )
91+ }
6092}
6193
6294/// Returns 'true' if the destination type is valid.
@@ -129,16 +161,21 @@ impl<N: Network, const VARIANT: u8> CommitInstruction<N, VARIANT> {
129161macro_rules! do_commit {
130162 ( $N: ident, $variant: expr, $destination_type: expr, $input: expr, $randomizer: expr, $ty: ty, $q: expr) => { {
131163 let func = match $variant {
132- 0 => $N:: commit_to_group_bhp256,
133- 1 => $N:: commit_to_group_bhp512,
134- 2 => $N:: commit_to_group_bhp768,
135- 3 => $N:: commit_to_group_bhp1024,
136- 4 => $N:: commit_to_group_ped64,
137- 5 => $N:: commit_to_group_ped128,
138- 6 .. => bail!( "Invalid 'commit' variant: {}" , $variant) ,
164+ 0 | 6 => $N:: commit_to_group_bhp256,
165+ 1 | 7 => $N:: commit_to_group_bhp512,
166+ 2 | 8 => $N:: commit_to_group_bhp768,
167+ 3 | 9 => $N:: commit_to_group_bhp1024,
168+ 4 | 10 => $N:: commit_to_group_ped64,
169+ 5 | 11 => $N:: commit_to_group_ped128,
170+ 12 .. => bail!( "Invalid 'commit' variant: {}" , $variant) ,
139171 } ;
140172
141- let literal_output: $ty = $q( func( & $input. to_bits_le( ) , $randomizer) ) ?. into( ) ;
173+ let bits = match CommitVariant :: is_raw( $variant) {
174+ true => $input. to_bits_raw_le( ) ,
175+ false => $input. to_bits_le( ) ,
176+ } ;
177+
178+ let literal_output: $ty = $q( func( & bits, $randomizer) ) ?. into( ) ;
142179 literal_output. cast_lossy( $destination_type) ?
143180 } } ;
144181}
@@ -196,7 +233,7 @@ impl<N: Network, const VARIANT: u8> CommitInstruction<N, VARIANT> {
196233 stack : & impl StackTrait < N > ,
197234 registers : & mut impl RegistersCircuit < N , A > ,
198235 ) -> Result < ( ) > {
199- use circuit:: traits:: ToBits ;
236+ use circuit:: traits:: { ToBits , ToBitsRaw } ;
200237
201238 // Ensure the number of operands is correct.
202239 if self . operands . len ( ) != 2 {
@@ -251,8 +288,8 @@ impl<N: Network, const VARIANT: u8> CommitInstruction<N, VARIANT> {
251288 // TODO (howardwu): If the operation is Pedersen, check that it is within the number of bits.
252289
253290 match VARIANT {
254- 0 ..=5 => Ok ( vec ! [ RegisterType :: Plaintext ( PlaintextType :: Literal ( self . destination_type) ) ] ) ,
255- 6 .. => bail ! ( "Invalid 'commit' variant: {VARIANT}" ) ,
291+ 0 ..=11 => Ok ( vec ! [ RegisterType :: Plaintext ( PlaintextType :: Literal ( self . destination_type) ) ] ) ,
292+ 12 .. => bail ! ( "Invalid 'commit' variant: {VARIANT}" ) ,
256293 }
257294 }
258295}
@@ -397,4 +434,46 @@ mod tests {
397434 assert_eq ! ( commit. destination_type, * destination_type, "The destination type is incorrect" ) ;
398435 }
399436 }
437+
438+ #[ test]
439+ fn test_parse_raw ( ) {
440+ for destination_type in valid_destination_types ( ) {
441+ let instruction = format ! ( "commit.bhp256.raw r0 r1 into r2 as {destination_type}" ) ;
442+ let ( string, commit) = CommitBHP256Raw :: < CurrentNetwork > :: parse ( & instruction) . unwrap ( ) ;
443+ assert ! ( string. is_empty( ) , "Parser did not consume all of the string: '{string}'" ) ;
444+ assert_eq ! ( commit. operands. len( ) , 2 , "The number of operands is incorrect" ) ;
445+ assert_eq ! ( commit. operands[ 0 ] , Operand :: Register ( Register :: Locator ( 0 ) ) , "The first operand is incorrect" ) ;
446+ assert_eq ! ( commit. operands[ 1 ] , Operand :: Register ( Register :: Locator ( 1 ) ) , "The second operand is incorrect" ) ;
447+ assert_eq ! ( commit. destination, Register :: Locator ( 2 ) , "The destination register is incorrect" ) ;
448+ assert_eq ! ( commit. destination_type, * destination_type, "The destination type is incorrect" ) ;
449+ }
450+ }
451+
452+ #[ test]
453+ fn test_raw_differs_from_standard ( ) {
454+ use console:: {
455+ program:: { Literal , Plaintext , Value } ,
456+ types:: { Field , Scalar } ,
457+ } ;
458+
459+ type N = CurrentNetwork ;
460+
461+ // Use a non-trivial field literal (not zero) so the bits actually differ between
462+ // to_bits_le (type-tagged) and to_bits_raw_le (untagged).
463+ let input_field = Field :: < N > :: one ( ) ;
464+ let randomizer = Scalar :: < N > :: one ( ) ;
465+ let value = Value :: Plaintext ( Plaintext :: from ( Literal :: Field ( input_field) ) ) ;
466+
467+ let standard = evaluate_commit ( CommitVariant :: CommitBHP256 , & value, & randomizer, LiteralType :: Field ) . unwrap ( ) ;
468+ let raw = evaluate_commit ( CommitVariant :: CommitBHP256Raw , & value, & randomizer, LiteralType :: Field ) . unwrap ( ) ;
469+
470+ assert_ne ! (
471+ standard, raw,
472+ "commit.bhp256 and commit.bhp256.raw must produce different outputs for the same input"
473+ ) ;
474+
475+ // Check that committing on the field element is equivalent to the raw commit via the instruction.
476+ let expected_commitment = N :: commit_bhp256 ( & input_field. to_bits_le ( ) , & randomizer) . unwrap ( ) ;
477+ assert_eq ! ( Literal :: Field ( expected_commitment) , raw) ;
478+ }
400479}
0 commit comments